﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область ПрограммныйИнтерфейс

// Устанавливает отчету переданную схему и на основании нее, инициализирует компоновщик настроек.
// Если контекстом является форма отчета (настроек), то обновляет основной реквизит формы - Отчет.
// В результате, контекст объекта и формы отчета синхронизируются.
// Вызывается например, из обработчика ПередЗагрузкойНастроекВКомпоновщик объекта универсального отчета
// для установки схемы, программно сформированной на основании другого объекта метаданных.
//
// Параметры:
//  Отчет - ОтчетОбъект
//        - ВнешнийОтчет - СКД-отчет, которому необходимо установить схему.
//  Контекст - ФормаКлиентскогоПриложения - форма отчета или форма настройки отчета.
//             Передается "как есть" из одноименного параметра события ПередЗагрузкойНастроекВКомпоновщик.
//           - Структура:
//               * СсылкаОтчета - Произвольный     - ссылка отчета.
//               * ПолноеИмя - Строка           - полное имя отчета.
//               * Метаданные - ОбъектМетаданных - метаданные отчета.
//               * Объект - ОтчетОбъект
//                        - ВнешнийОтчет - объект отчета:
//                            ** КомпоновщикНастроек - КомпоновщикНастроекКомпоновкиДанных - настройки отчета.
//                            ** СхемаКомпоновкиДанных - СхемаКомпоновкиДанных - схема отчета.
//               * КлючВарианта - Строка - имя предопределенного или идентификатор пользовательского варианта отчета.
//               * АдресСхемы - Строка - адрес временного хранилища, по которому размещена схема отчета.
//               * Успех - Булево - Истина, если удалось подключить отчет.
//               * ТекстОшибки - Строка - текст ошибки.
//       
//       
//  Схема - СхемаКомпоновкиДанных - схема, которую необходимо установить отчету.
//  КлючСхемы - Строка - идентификатор новой схемы, который будет записан в дополнительные свойства 
//                       пользовательских настроек.
//
// Пример:
//  // В обработчике объекта отчета ПередЗагрузкойНастроекВКомпоновщик компоновщик настроек
//  // инициализируется на основании схемы из общих макетов:
//  Если КлючСхемы <> "1" Тогда
//  	  КлючСхемы = "1";
//  	  Схема = ПолучитьОбщийМакет("МояОбщаяСхемаКомпоновки");
//  	  ОтчетыСервер.ПодключитьСхему(ЭтотОбъект, Контекст, Схема, КлючСхемы);
//  КонецЕсли;
//
Процедура ПодключитьСхему(Отчет, Контекст, Схема, КлючСхемы) Экспорт
	СобытиеФормы = (ТипЗнч(Контекст) = Тип("ФормаКлиентскогоПриложения"));
	
	Отчет.СхемаКомпоновкиДанных = Схема;
	Если СобытиеФормы Тогда
		НастройкиОтчета = Контекст.НастройкиОтчета;
		АдресСхемы = НастройкиОтчета.АдресСхемы;
		НастройкиОтчета.СхемаМодифицирована = Истина;
	Иначе
		АдресСхемыЗаполнен = (ТипЗнч(Контекст.АдресСхемы) = Тип("Строка") И ЭтоАдресВременногоХранилища(Контекст.АдресСхемы));
		Если Не АдресСхемыЗаполнен Тогда
			ИдентификаторФормы = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "ИдентификаторФормы");
			Если ТипЗнч(ИдентификаторФормы) = Тип("УникальныйИдентификатор") Тогда
				АдресСхемыЗаполнен = Истина;
				Контекст.АдресСхемы = ПоместитьВоВременноеХранилище(Схема, ИдентификаторФормы);
			КонецЕсли;
		КонецЕсли;
		Если АдресСхемыЗаполнен Тогда
			АдресСхемы = Контекст.АдресСхемы;
		Иначе
			АдресСхемы = ПоместитьВоВременноеХранилище(Схема);
		КонецЕсли;
		Контекст.СхемаМодифицирована = Истина;
	КонецЕсли;
	ПоместитьВоВременноеХранилище(Схема, АдресСхемы);
	
	ВариантОтчета = ?(СобытиеФормы, НастройкиОтчета.ВариантСсылка, Неопределено);
	ИнициализироватьКомпоновщикНастроек(Отчет.КомпоновщикНастроек, АдресСхемы, Отчет, ВариантОтчета);
	
	Если СобытиеФормы Тогда
		ЗначениеВДанныеФормы(Отчет, Контекст.Отчет);
	КонецЕсли;
КонецПроцедуры

// Инициализирует компоновщик настроек компоновки данных, с обработкой исключения.
//
// Параметры:
//  КомпоновщикНастроек - КомпоновщикНастроекКомпоновкиДанных - компоновщик настроек, который необходимо инициализировать.
//  Схема - СхемаКомпоновкиДанных
//        - Строка.
//  Отчет - ОтчетОбъект
//        - Неопределено - отчет, чей компоновщик инициализируется.
//  ВариантОтчета - СправочникСсылка.ВариантыОтчетов
//                - Неопределено - хранилище варианта отчета.
//
Процедура ИнициализироватьКомпоновщикНастроек(КомпоновщикНастроек, Схема, Отчет = Неопределено, ВариантОтчета = Неопределено) Экспорт 
	Попытка
		КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(Схема));
	Исключение
		ИмяСобытия = НСтр("ru = 'Ошибка инициализации компоновщика настроек компоновки данных.'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		
		ОбъектМетаданных = Неопределено;
		Если Отчет <> Неопределено Тогда 
			ОбъектМетаданных = Отчет.Метаданные();
		ИначеЕсли ВариантОтчета <> Неопределено Тогда 
			ОбъектМетаданных = ВариантОтчета.Метаданные();
		КонецЕсли;
		
		Комментарий = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		
		ЗаписьЖурналаРегистрации(
			ИмяСобытия, УровеньЖурналаРегистрации.Ошибка, ОбъектМетаданных, ВариантОтчета, Комментарий);
		
		ВызватьИсключение;
	КонецПопытки;
КонецПроцедуры

// Выводит команду в форму отчета в виде кнопки в указанную группу.
// Также регистрирует команду, защищая ее от удаления при перерисовке формы.
// Для вызова из события ПриСозданииНаСервере формы отчета.
//
// Параметры:
//   ФормаОтчета - ФормаКлиентскогоПриложения
//               - РасширениеУправляемойФормыДляОтчета - форма, где:
//     * ПостоянныеРеквизиты - СписокЗначений
//     * ПостоянныеКоманды - СписокЗначений
//   КомандаИлиКоманды - КомандаФормы     - команда, с которой будут связаны выводимые кнопки.
//                       Если в свойстве Действие указана пустая строка,
//                       то при выполнении команды будет вызвана процедура ОтчетыКлиентПереопределяемый.ОбработчикКоманды.
//                       Если в свойстве Действие указана строка вида "<ИмяКлиентскогоОбщегоМодуля>.<ИмяЭкспортнойПроцедуры>",
//                       то при выполнении команды в указанном модуле будет вызвана указанная процедура с двумя параметрами,
//                       аналогичным двум первым параметрам процедуры ОтчетыКлиентПереопределяемый.ОбработчикКоманды.
//                     - Массив - набор команд (КомандаФормы), которые будут выведены в указанную группу.
//   ТипГруппы - Строка - условное имя группы, в которой требуется вывести кнопку.
//               "Главное"          - группа с кнопками "Сформировать" и "Формировать сразу".
//               "Настройки"        - группа с кнопками "Настройки", "Изменить вариант отчета" и т.п.
//               "РаботаСТабличнымДокументом" - группа с кнопками "Найти", "Развернуть все группы" и т.п.
//               "Интеграция"       - группа такими кнопками как "Печать, Сохранить, Отправить" и т.п.
//               "ПодменюОтправить" - подменю в группе "Интеграция" для отправки по почте.
//               "Прочее"           - группа с кнопками "Изменить форму", "Справка" и т.п.
//   ВНачалоГруппы - Булево - если Истина, то кнопка будет выведена в начале группы. Иначе в конце группы.
//   ТолькоВоВсехДействиях - Булево - если Истина, то кнопка будет выведена только в подменю "Еще".
//                           Иначе и в подменю "Еще", и в командной панели формы.
//   СуффиксПодгруппы - Строка - если заполнен, то команды будут объединены в подгруппу.
//                      СуффиксПодгруппы добавляется к имени группы справа.
//
Процедура ВывестиКоманду(ФормаОтчета, КомандаИлиКоманды, ТипГруппы, ВНачалоГруппы = Ложь, ТолькоВоВсехДействиях = Ложь, СуффиксПодгруппы = "") Экспорт
	ПередЧемВставить = Неопределено;
	ГруппаЕще = Неопределено;
	
	Если ТипГруппы = "Главное" Тогда
		Группа = ФормаОтчета.Элементы.ГруппаГлавное;
		ГруппаЕще = ФормаОтчета.Элементы.ГруппаГлавноеЕще;
	ИначеЕсли ТипГруппы = "Настройки" Тогда
		Группа = ФормаОтчета.Элементы.ГруппаНастройкиОтчета;
		ГруппаЕще = ФормаОтчета.Элементы.ГруппаНастройкиОтчетаЕще;
	ИначеЕсли ТипГруппы = "РаботаСТабличнымДокументом" Тогда
		Группа = ФормаОтчета.Элементы.ГруппаРаботаВТаблице;
		ГруппаЕще = ФормаОтчета.Элементы.ГруппаРаботаВТаблицеЕще;
	ИначеЕсли ТипГруппы = "Интеграция" Тогда
		Группа = ФормаОтчета.Элементы.ГруппаВывод;
		ГруппаЕще = ФормаОтчета.Элементы.ГруппаВыводЕще;
	ИначеЕсли ТипГруппы = "ПодменюОтправить" Тогда
		Группа = ФормаОтчета.Элементы.ГруппаОтправить;
		ГруппаЕще = ФормаОтчета.Элементы.ГруппаОтправитьЕще;
	ИначеЕсли ТипГруппы = "Прочее" Тогда
		Группа = ФормаОтчета.Элементы.ОсновнаяКоманднаяПанель;
		ГруппаЕще = ФормаОтчета.Элементы.КоманднаяПанельЕще;
		ПередЧемВставить = ?(ВНачалоГруппы, ФормаОтчета.Элементы.НовоеОкно, Неопределено);
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'При вызове процедуры ""%1"" передано недопустимо значение параметра ""%2"".'"),
			"ОтчетыСервер.ВывестиКоманду",
			"ТипГруппы");
	КонецЕсли;
	
	Если ТолькоВоВсехДействиях Тогда 
		Группа = ГруппаЕще;
		ГруппаЕще = Неопределено;
	КонецЕсли;
	
	Если ВНачалоГруппы И ПередЧемВставить = Неопределено Тогда
		ПередЧемВставить = Группа.ПодчиненныеЭлементы[0];
	КонецЕсли;
	
	Если ТипЗнч(КомандаИлиКоманды) = Тип("КомандаФормы") Тогда
		Команды = Новый Массив;
		Команды.Добавить(КомандаИлиКоманды);
	Иначе
		Команды = КомандаИлиКоманды;
	КонецЕсли;
	
	Если СуффиксПодгруппы <> "" Тогда
		Подгруппа = ФормаОтчета.Элементы.Найти(Группа.Имя + СуффиксПодгруппы);
		Если Подгруппа = Неопределено Тогда
			Подгруппа = ФормаОтчета.Элементы.Вставить(Группа.Имя + СуффиксПодгруппы, Тип("ГруппаФормы"), Группа, ПередЧемВставить);
			Если Подгруппа.Вид = ВидГруппыФормы.Подменю Тогда
				Подгруппа.Вид = ВидГруппыФормы.ГруппаКнопок;
			КонецЕсли;
		КонецЕсли;
		Группа = Подгруппа;
		ПередЧемВставить = Неопределено;
	КонецЕсли;
	
	Для Каждого Команда Из Команды Цикл
		Обработчик = ?(СтрЧислоВхождений(Команда.Действие, ".") = 0, "", Команда.Действие);
		ФормаОтчета.ПостоянныеКоманды.Добавить(Команда.Имя, Обработчик);
		Команда.Действие = "Подключаемый_Команда";
		
		Кнопка = ФормаОтчета.Элементы.Вставить(Команда.Имя, Тип("КнопкаФормы"), Группа, ПередЧемВставить);
		Кнопка.ИмяКоманды = Команда.Имя;
		
		Если ГруппаЕще = Неопределено Тогда 
			Кнопка.ПоложениеВКоманднойПанели = ?(ТолькоВоВсехДействиях, 
				ПоложениеКнопкиВКоманднойПанели.ВДополнительномПодменю, ПоложениеКнопкиВКоманднойПанели.ВКоманднойПанели);
			Продолжить;
		КонецЕсли;
		
		Кнопка = ФормаОтчета.Элементы.Вставить(Команда.Имя + "Еще", Тип("КнопкаФормы"), ГруппаЕще);
		Кнопка.ИмяКоманды = Команда.Имя;
		Кнопка.ПоложениеВКоманднойПанели = ПоложениеКнопкиВКоманднойПанели.ВДополнительномПодменю;
	КонецЦикла;
КонецПроцедуры

// Оформляет ячейку в виде гиперссылки и заполняет поля адреса и представления ссылки.
//
// Параметры:
//   Ячейка      - ОбластьЯчеекТабличногоДокумента - область табличного документа.
//   АдресСсылки - Строка                          - адрес ссылки, которую необходимо вывести в указанной ячейке.
//			       В стандартной форме отчета автоматически открываются ссылки следующих форматов:
//			       "http://<адрес>", "https://<адрес>", "e1cib/<адрес>", "e1c://<адрес>"
//			       Такие ссылки открываются при помощи процедуры ОбщегоНазначенияКлиент.ОткрытьНавигационнуюСсылку.
//			       См. также ПредставлениеНавигационнойСсылки.НавигационнаяСсылка в синтакс-помощнике.
//			       Для открытия ссылок других форматов следует написать код
//			       в процедуре ОтчетыКлиентПереопределяемый.ОбработкаВыбораТабличногоДокумента.
//   ПредставлениеСсылки - Строка
//                       - Неопределено - наименование, которую необходимо вывести в указанной ячейке.
//                                        Если Неопределено, то выводится как есть АдресСсылки.
//
Процедура ВывестиГиперссылку(Ячейка, АдресСсылки, ПредставлениеСсылки = Неопределено) Экспорт
	Ячейка.Гиперссылка = Истина;
	Ячейка.Шрифт       = Новый Шрифт(Ячейка.Шрифт, , , , , Истина); // АПК:1345 Шрифт формируется на основании шрифта ячейки, который может быть произвольным и зависеть от макета оформления отчета.
	Ячейка.ЦветТекста  = Метаданные.ЭлементыСтиля.ГиперссылкаЦвет.Значение;
	Ячейка.Расшифровка = АдресСсылки;
	Ячейка.Текст       = ?(ПредставлениеСсылки = Неопределено, АдресСсылки, ПредставлениеСсылки);
КонецПроцедуры

// Определяет, что отчет пустой.
//
// Параметры:
//   ОтчетОбъект - ОтчетОбъект
//               - ВнешнийОтчет - проверяемый отчет.
//   ПроцессорКД - ПроцессорКомпоновкиДанных - объект, выполняющий компоновку данных в отчете.
//
// Возвращаемое значение:
//   Булево - Истина, если отчет пустой. Ложь, если отчет содержит данные.
//
Функция ОтчетПустой(ОтчетОбъект, ПроцессорКД = Неопределено) Экспорт
	Если ПроцессорКД = Неопределено Тогда
		
		Если ОтчетОбъект.СхемаКомпоновкиДанных = Неопределено Тогда
			Возврат Ложь; // Не СКД отчет.
		КонецЕсли;
		
		// Объект для создания макета компоновки данных.
		КомпоновщикМакетаКД = Новый КомпоновщикМакетаКомпоновкиДанных;
		
		// Выполняет компоновку макета.
		МакетКД = КомпоновщикМакетаКД.Выполнить(ОтчетОбъект.СхемаКомпоновкиДанных, ОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки());
		
		// Пропуск проверки на то, что отчет пустой.
		Если ЕстьВнешнийНаборДанных(МакетКД.НаборыДанных) Тогда
			Возврат Ложь;
		КонецЕсли;
		
		// Объект, выполняющий компоновку данных.
		ПроцессорКД = Новый ПроцессорКомпоновкиДанных;
		
		// Инициализировать объект.
		ПроцессорКД.Инициализировать(МакетКД, , , Истина);
		
	Иначе
		
		// Встать в начало компоновки.
		ПроцессорКД.Сбросить();
		
	КонецЕсли;
	
	// Объект для вывода результата компоновки в табличный документ.
	ПроцессорВыводаРезультатаКД = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
	
	// Устанавливает табличный документ, в который нужно выводить результат.
	ПроцессорВыводаРезультатаКД.УстановитьДокумент(Новый ТабличныйДокумент);
	
	// Последовательный вывод
	ПроцессорВыводаРезультатаКД.НачатьВывод();
	
	// Получает следующий элемент результата компоновки.
	ЭлементРезультатаКД = ПроцессорКД.Следующий();
	Пока ЭлементРезультатаКД <> Неопределено Цикл
		
		// Вывести элемент результата компоновки отчета в документ.
		ПроцессорВыводаРезультатаКД.ВывестиЭлемент(ЭлементРезультатаКД);
		
		// Определить не пустой результат.
		Для Каждого ЗначениеПараметраМакетаКД Из ЭлементРезультатаКД.ЗначенияПараметров Цикл
			Попытка
				ЗначениеЗаполнено = ЗначениеЗаполнено(ЗначениеПараметраМакетаКД.Значение);
			Исключение
				ЗначениеЗаполнено = Ложь; // Линия, Рамка, Цвет и другие объекты КД, которые могут фигурировать при выводе.
			КонецПопытки;
			Если ЗначениеЗаполнено Тогда
				ПроцессорВыводаРезультатаКД.ЗакончитьВывод();
				Возврат Ложь;
			КонецЕсли;
		КонецЦикла;
		
		Попытка
			// Получает следующий элемент результата компоновки.
			ЭлементРезультатаКД = ПроцессорКД.Следующий();
		Исключение
			Возврат Ложь;
		КонецПопытки;
		
	КонецЦикла;
	
	// Указание объекту о том, что вывод результата завершен.
	ПроцессорВыводаРезультатаКД.ЗакончитьВывод();
	
	Возврат Истина;
КонецФункции

// Возвращает коллекцию свойств элементов формы отчета (настроек отчета), связанные с настройками,
// которые доступны для переопределения в модуле объекта отчета.
// 
// Параметры:
//   ТипФормы - ТипФормыОтчета
//   КомпоновщикНастроек - КомпоновщикНастроекКомпоновкиДанных
//   ДополнительныеПараметры - см. ОтчетыКлиентСервер.НастройкиОтчетаПоУмолчанию
// 
// Возвращаемое значение:
//   Структура:
//   * Группы - см. СвойстваГруппыЭлементовФормы
//   * Поля - ТаблицаЗначений:
//       ** ИндексНастройки - Число
//       ** ИдентификаторНастройки  - Строка
//       ** Настройки - НастройкиКомпоновкиДанных
//       ** ЭлементНастройки - ЭлементОтбораКомпоновкиДанных
//                           - ЗначениеПараметраНастроекКомпоновкиДанных
//                           - ВыбранноеПолеКомпоновкиДанных
//                           - ЭлементПорядкаКомпоновкиДанных
//                           - ЭлементУсловногоОформления
//       ** ОписаниеНастройки - ДоступноеПолеОтбораКомпоновкиДанных
//                            - ДоступныеПараметрыКомпоновкиДанных
//                            - ДоступноеПолеКомпоновкиДанных
//       ** Представление - Строка
//       ** ИдентификаторГруппы - Строка
//       ** ПоложениеЗаголовка - ПоложениеЗаголовкаЭлементаФормы
//       ** РастягиватьПоГоризонтали - Булево
//                                   - Неопределено
//       ** Ширина - Число
//
Функция СвойстваЭлементовФормыНастроек(ТипФормы, КомпоновщикНастроек, ДополнительныеПараметры) Экспорт
	
	СвойстваЭлементов = Новый Структура("Группы, Поля");
	СвойстваЭлементов.Группы = Новый Структура;
	
	Поля = ПоляЭлементовФормыНастроек();
	
	ДоступныеРежимы = Новый Массив;
	ДоступныеРежимы.Добавить(РежимОтображенияЭлементаНастройкиКомпоновкиДанных.БыстрыйДоступ);
	Если ТипФормы = ТипФормыОтчета.Настройка Тогда 
		ДоступныеРежимы.Добавить(РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный);
	КонецЕсли;
	
	НедоступныеЭлементыСтруктуры = Новый Соответствие;
	НедоступныеЭлементыСтруктуры.Вставить(Тип("ГруппировкаКомпоновкиДанных"), ТипФормыОтчета.Настройка);
	НедоступныеЭлементыСтруктуры.Вставить(Тип("ГруппировкаТаблицыКомпоновкиДанных"), ТипФормыОтчета.Настройка);
	НедоступныеЭлементыСтруктуры.Вставить(Тип("ГруппировкаДиаграммыКомпоновкиДанных"), ТипФормыОтчета.Настройка);
	НедоступныеЭлементыСтруктуры.Вставить(Тип("ТаблицаКомпоновкиДанных"), ТипФормыОтчета.Настройка);
	НедоступныеЭлементыСтруктуры.Вставить(Тип("ДиаграммаКомпоновкиДанных"), ТипФормыОтчета.Настройка);
	
	Сведения = СведенияОПользовательскихНастройках(КомпоновщикНастроек.Настройки);
	ПользовательскиеНастройки = КомпоновщикНастроек.ПользовательскиеНастройки;
	Для Каждого ЭлементПользовательскойНастройки Из ПользовательскиеНастройки.Элементы Цикл 
		НайденныеСведения = Сведения[ЭлементПользовательскойНастройки.ИдентификаторПользовательскойНастройки];
		Если НайденныеСведения = Неопределено Тогда 
			Продолжить;
		КонецЕсли;

		ЭлементНастройки = НайденныеСведения.ЭлементНастройки; // ГруппировкаКомпоновкиДанных, ГруппировкаТаблицыКомпоновкиДанных, ГруппировкаДиаграммыКомпоновкиДанных 
		Если ЭлементНастройки = Неопределено
			Или НедоступныеЭлементыСтруктуры.Получить(ТипЗнч(ЭлементНастройки)) = ТипФормы
			Или ДоступныеРежимы.Найти(ЭлементНастройки.РежимОтображения) = Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		
		ТипЭлемента = ТипЗнч(ЭлементНастройки);
		Если ТипЭлемента = Тип("ЭлементУсловногоОформленияКомпоновкиДанных") Тогда 
			Представление = ОтчетыКлиентСервер.ПредставлениеЭлементаУсловногоОформления(
				ЭлементНастройки, Неопределено, "");
			
			Если Не ЗначениеЗаполнено(ЭлементНастройки.Представление) Тогда 
				ЭлементНастройки.Представление = Представление;
			ИначеЕсли Не ЗначениеЗаполнено(ЭлементНастройки.ПредставлениеПользовательскойНастройки)
				И ЭлементНастройки.Представление <> Представление Тогда 
				
				ЭлементНастройки.ПредставлениеПользовательскойНастройки = ЭлементНастройки.Представление;
				ЭлементНастройки.Представление = Представление;
			КонецЕсли;
		КонецЕсли;
		
		Поле = Поля.Добавить();
		Поле.ИдентификаторНастройки = ЭлементПользовательскойНастройки.ИдентификаторПользовательскойНастройки;
		Поле.ИндексНастройки = ПользовательскиеНастройки.Элементы.Индекс(ЭлементПользовательскойНастройки);
		Поле.Настройки = НайденныеСведения.Настройки;
		Поле.ЭлементНастройки = ЭлементНастройки;
		Поле.ОписаниеНастройки = НайденныеСведения.ОписаниеНастройки;
		Поле.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Авто;
		
		Если НедоступныеЭлементыСтруктуры.Получить(ТипЗнч(ЭлементНастройки)) <> Неопределено Тогда 
			Представление = ЭлементНастройки.ПараметрыВывода.Элементы.Найти("TITLE");
			Если Представление <> Неопределено
				И ЗначениеЗаполнено(Представление.Значение) Тогда 
				Поле.Представление = Представление.Значение;
			КонецЕсли;
		КонецЕсли;
		
		Если ТипФормы = ТипФормыОтчета.Настройка
			И ТипЗнч(ЭлементНастройки) = Тип("ЭлементУсловногоОформленияКомпоновкиДанных") Тогда 
			Поле.ИдентификаторГруппы = "Дополнительно";
		КонецЕсли;
	КонецЦикла;
	
	Если Поля.Найти("Дополнительно", "ИдентификаторГруппы") <> Неопределено Тогда 
		СвойстваЭлементов.Группы.Вставить("Дополнительно", СвойстваГруппыЭлементовФормы());
	КонецЕсли;
	
	Поля.Сортировать("ИндексНастройки");
	СвойстваЭлементов.Поля = Поля;
	
	Если ДополнительныеПараметры.События.ПриОпределенииСвойствЭлементовФормыНастроек Тогда 
		ОтчетОбъект(ДополнительныеПараметры.ПолноеИмя).ПриОпределенииСвойствЭлементовФормыНастроек(
			ТипФормы, СвойстваЭлементов, ПользовательскиеНастройки.Элементы);
	КонецЕсли;
	
	Возврат СвойстваЭлементов;
КонецФункции

// Конструктор свойств группы элементов формы пользовательских настроек.
//
// Возвращаемое значение:
//   Структура - содержит значения свойств группы:
//    * Отображение - ОтображениеОбычнойГруппы - см. Синтакс-помощник - ОтображениеОбычнойГруппы.
//    * Группировка - ГруппировкаПодчиненныхЭлементовФормы - количество групп-колонок элементов:
//       ** Вертикальная - ГруппировкаПодчиненныхЭлементовФормы - эквивалентно 1-ой колонке;
//       ** ГоризонтальнаяЕслиВозможно - ГруппировкаПодчиненныхЭлементовФормы - эквивалентно 2-м колонкам;
//       ** ГоризонтальнаяВсегда - ГруппировкаПодчиненныхЭлементовФормы - количество колонок равно количеству элементов
//                                                                        в группе.
//    * Заголовок - Строка - см. синтакс-помощник - ГруппаФормы.Заголовок
//    * ЦветФона - Цвет - см. синтакс-помощник - ГруппаФормы.ЦветФона
//    * Подсказка - Строка - см. синтакс-помощник - ГруппаФормы.Подсказка
//    * ОтображениеПодсказки - ОтображениеПодсказки - см. синтакс-помощник - ГруппаФормы.ОтображениеПодсказки
//    * Высота - Число - см. синтакс-помощник - ГруппаФормы.Высота
//    * Ширина - Число - см. синтакс-помощник - ГруппаФормы.Ширина
//    * РастягиватьПоВертикали - Неопределено, Булево - см. синтакс-помощник - ГруппаФормы.РастягиватьПоВертикали
//    * РастягиватьПоГоризонтали - Неопределено, Булево - см. синтакс-помощник - ГруппаФормы.РастягиватьПоГоризонтали
//
Функция СвойстваГруппыЭлементовФормы() Экспорт 
	СвойстваГруппы = Новый Структура;
	СвойстваГруппы.Вставить("Отображение", ОтображениеОбычнойГруппы.Нет);
	СвойстваГруппы.Вставить("Группировка", ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяЕслиВозможно);
	
	СвойстваГруппы.Вставить("Заголовок", "");
	СвойстваГруппы.Вставить("ЦветФона", Новый Цвет);

	СвойстваГруппы.Вставить("Подсказка", "");
	СвойстваГруппы.Вставить("ОтображениеПодсказки", ОтображениеПодсказки.Авто);

	СвойстваГруппы.Вставить("Высота", 0);
	СвойстваГруппы.Вставить("Ширина", 0);
	СвойстваГруппы.Вставить("РастягиватьПоВертикали", Неопределено);
	СвойстваГруппы.Вставить("РастягиватьПоГоризонтали", Неопределено);
	
	Возврат СвойстваГруппы;
КонецФункции

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

// Выводит и группирует элементы формы, связанные с пользовательскими настройками.
// Форма содержит тип РасширениеУправляемойФормыДляОтчета.
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//         - РасширениеУправляемойФормыДляКомпоновщикаНастроек
//   УзелИерархииЭлементов - ГруппаФормы
//   ПараметрыОбновления - Структура
//                       - Неопределено
//
Процедура ОбновитьЭлементыФормыНастроек(Форма, УзелИерархииЭлементов, ПараметрыОбновления = Неопределено) Экспорт 
	ПередОбновлениемЭлементовФормыНастроек(Форма, ПараметрыОбновления);
	
	Если ОбщегоНазначения.ЭтоМобильныйКлиент() Тогда 
		Форма.СоздатьЭлементыФормыПользовательскихНастроек(УзелИерархииЭлементов);
		Возврат;
	КонецЕсли;
	
	Элементы = Форма.Элементы;
	НастройкиОтчета = Форма.НастройкиОтчета;
	
	ВидыСтилизованныхЭлементов = СтрРазделить("Период, Список, Флажок", ", ", Ложь);
	ИменаРеквизитов = ИменаРеквизитовЭлементовНастроек(Форма, ВидыСтилизованныхЭлементов);
	
	ПодготовитьФормуКПерегруппировкеЭлементов(Форма, УзелИерархииЭлементов, ИменаРеквизитов, ВидыСтилизованныхЭлементов);
	
	ВременнаяГруппа = Элементы.Добавить("Временная", Тип("ГруппаФормы"));
	ВременнаяГруппа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
	
	Режим = РежимОтображенияНастроекКомпоновкиДанных.БыстрыйДоступ;
	Если Форма.ТипФормыОтчета = ТипФормыОтчета.Настройка Тогда 
		Режим = РежимОтображенияНастроекКомпоновкиДанных.Все;
	КонецЕсли;
	
	Форма.СоздатьЭлементыФормыПользовательскихНастроек(ВременнаяГруппа, Режим, 1);
	
	СвойстваЭлементов = СвойстваЭлементовФормыНастроек(
		Форма.ТипФормыОтчета, Форма.Отчет.КомпоновщикНастроек, НастройкиОтчета);
	
	ПерегруппироватьЭлементыФормыНастроек(
		Форма, УзелИерархииЭлементов, СвойстваЭлементов, ИменаРеквизитов, ВидыСтилизованныхЭлементов);
	
	Элементы.Удалить(ВременнаяГруппа);
	
	// Вызов переопределяемого модуля.
	Если НастройкиОтчета.События.ПослеЗаполненияПанелиБыстрыхНастроек Тогда
		ОтчетОбъект = ОтчетОбъект(НастройкиОтчета.ПолноеИмя);
		ОтчетОбъект.ПослеЗаполненияПанелиБыстрыхНастроек(Форма, ПараметрыОбновления);
	КонецЕсли;
КонецПроцедуры

Функция ДоступныеНастройки(ПараметрыЗагрузки, НастройкиОтчета) Экспорт 
	Настройки = Неопределено;
	ПользовательскиеНастройки = Неопределено;
	ФиксированныеНастройки = Неопределено;
	
	Если ПараметрыЗагрузки.Свойство("КомпоновщикНастроекКД") Тогда
		Настройки = ПараметрыЗагрузки.КомпоновщикНастроекКД.Настройки;
		ПользовательскиеНастройки = ПараметрыЗагрузки.КомпоновщикНастроекКД.ПользовательскиеНастройки;
		ФиксированныеНастройки = ПараметрыЗагрузки.КомпоновщикНастроекКД.ФиксированныеНастройки;
	Иначе
		Если ПараметрыЗагрузки.Свойство("НастройкиКД") Тогда
			Настройки = ПараметрыЗагрузки.НастройкиКД;
		КонецЕсли;
		Если ПараметрыЗагрузки.Свойство("ПользовательскиеНастройкиКД") Тогда
			ПользовательскиеНастройки = ПараметрыЗагрузки.ПользовательскиеНастройкиКД;
		КонецЕсли;
	КонецЕсли;
	
	Если НастройкиОтчета.События.ПередЗагрузкойНастроекВКомпоновщик Тогда
		Если ТипЗнч(НастройкиОтчета.НовыеНастройкиXML) = Тип("Строка") Тогда
			Попытка
				Настройки = ОбщегоНазначения.ЗначениеИзСтрокиXML(НастройкиОтчета.НовыеНастройкиXML);
				
				// Устанавливается связь со схемой, для восстановления неиспользовавшихся значений параметров данных,
				//  которые теряются при сериализации настроек (см. синтакс-помощник: ЗначенияПараметровДанныхКомпоновкиДанных).
				КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
				ИнициализироватьКомпоновщикНастроек(КомпоновщикНастроек, НастройкиОтчета.АдресСхемы);
				КомпоновщикНастроек.ЗагрузитьНастройки(Настройки);
				
				Настройки = КомпоновщикНастроек.Настройки;
			Исключение
				Настройки = Неопределено;
			КонецПопытки;
			НастройкиОтчета.НовыеНастройкиXML = Неопределено;
		КонецЕсли;
		
		Если ТипЗнч(НастройкиОтчета.НовыеПользовательскиеНастройкиXML) = Тип("Строка") Тогда
			Попытка
				ПользовательскиеНастройки = ОбщегоНазначения.ЗначениеИзСтрокиXML(
					НастройкиОтчета.НовыеПользовательскиеНастройкиXML);
			Исключение
				ПользовательскиеНастройки = Неопределено;
			КонецПопытки;
			НастройкиОтчета.НовыеПользовательскиеНастройкиXML = Неопределено;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Новый Структура("Настройки, ПользовательскиеНастройки, ФиксированныеНастройки",
		Настройки, ПользовательскиеНастройки, ФиксированныеНастройки);
КонецФункции

Процедура СброситьПользовательскиеНастройки(ДоступныеНастройки, ПараметрыЗагрузки) Экспорт 
	СброситьПользовательскиеНастройки = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
		ПараметрыЗагрузки, "СброситьПользовательскиеНастройки", Ложь);
	
	Если Не СброситьПользовательскиеНастройки Тогда 
		Возврат;
	КонецЕсли;
	
	Если ДоступныеНастройки.ПользовательскиеНастройки = Неопределено Тогда 
		ДополнительныеСвойства = Неопределено;
	Иначе
		ДополнительныеСвойства = ДоступныеНастройки.ПользовательскиеНастройки.ДополнительныеСвойства;
	КонецЕсли;
	
	ДоступныеНастройки.ПользовательскиеНастройки = Новый ПользовательскиеНастройкиКомпоновкиДанных;
	
	Если ДополнительныеСвойства = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	Для Каждого Свойство Из ДополнительныеСвойства Цикл 
		ДоступныеНастройки.ПользовательскиеНастройки.ДополнительныеСвойства.Вставить(Свойство.Ключ, Свойство.Значение);
	КонецЦикла;
КонецПроцедуры

Процедура ВосстановитьЗначенияОтборов(Форма) Экспорт 
	ПутьКДаннымЭлементов = Форма.ПутьКДаннымЭлементов;
	Если ПутьКДаннымЭлементов = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	ПользовательскиеНастройки = Форма.Отчет.КомпоновщикНастроек.ПользовательскиеНастройки;
	
	КэшЗначенийОтборов = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
		ПользовательскиеНастройки.ДополнительныеСвойства, "КэшЗначенийОтборов");
	
	Если КэшЗначенийОтборов = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	Для Каждого ЭлементКэша Из КэшЗначенийОтборов Цикл 
		ЗначениеОтбора = ЭлементКэша.Значение;
		Если ЗначениеОтбора.Количество() = 0 Тогда 
			Продолжить;
		КонецЕсли;
		
		ЭлементНастройки = ПользовательскиеНастройки.Элементы.Найти(ЭлементКэша.Ключ);
		Если ЭлементНастройки = Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		
		Индекс = ПользовательскиеНастройки.Элементы.Индекс(ЭлементНастройки);
		ИмяСписка = ПутьКДаннымЭлементов.ПоИндексу[Индекс];
		Если ИмяСписка = Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		
		Список = Форма[ИмяСписка];
		Если Список = Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		
		Для Каждого Элемент Из ЗначениеОтбора Цикл 
			Если Список.НайтиПоЗначению(Элемент.Значение) = Неопределено Тогда 
				Список.Добавить(Элемент.Значение);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

Процедура УстановитьДоступныеЗначения(Отчет, Форма) Экспорт 
	КомпоновщикНастроек = Форма.Отчет.КомпоновщикНастроек;
	
	КоллекцииНастроек = Новый Массив; // массив из ПользовательскиеНастройкиКомпоновкиДанных, ЗначенияПараметровДанныхКомпоновкиДанных, ОтборКомпоновкиДанных
	КоллекцииНастроек.Добавить(КомпоновщикНастроек.ПользовательскиеНастройки);
	КоллекцииНастроек.Добавить(КомпоновщикНастроек.Настройки.ПараметрыДанных);
	КоллекцииНастроек.Добавить(КомпоновщикНастроек.Настройки.Отбор);
	
	Для Каждого КоллекцияНастроек Из КоллекцииНастроек Цикл 
		ЭтоПользовательскиеНастройки = (ТипЗнч(КоллекцияНастроек) = Тип("ПользовательскиеНастройкиКомпоновкиДанных"));
		
		Для Каждого ЭлементНастройки Из КоллекцияНастроек.Элементы Цикл 
			Если ТипЗнч(ЭлементНастройки) <> Тип("ЗначениеПараметраНастроекКомпоновкиДанных")
				И ТипЗнч(ЭлементНастройки) <> Тип("ЭлементОтбораКомпоновкиДанных") Тогда 
				Продолжить;
			КонецЕсли;
			
			Если Не ЭтоПользовательскиеНастройки
				И ЗначениеЗаполнено(ЭлементНастройки.ИдентификаторПользовательскойНастройки) Тогда 
				Продолжить;
			КонецЕсли;
			
			Если ЭтоПользовательскиеНастройки Тогда 
				ЭлементПользовательскойНастройки = ЭлементНастройки;
				
				ЭлементОсновнойНастройки = ОтчетыКлиентСервер.ПолучитьОбъектПоПользовательскомуИдентификатору(
					КомпоновщикНастроек.Настройки,
					ЭлементПользовательскойНастройки.ИдентификаторПользовательскойНастройки,,
					КоллекцияНастроек);
			Иначе
				ЭлементПользовательскойНастройки = ЭлементНастройки;
				ЭлементОсновнойНастройки = ЭлементНастройки;
			КонецЕсли;
			
			ОписаниеНастройки = ОтчетыКлиентСервер.НайтиДоступнуюНастройку(
				КомпоновщикНастроек.Настройки, ЭлементОсновнойНастройки);
			// @skip-check query-in-loop - запрос к разным таблицам.
			УстановитьДоступныеЗначенияНастроек(Форма, Отчет, КомпоновщикНастроек, ЭлементПользовательскойНастройки, ЭлементОсновнойНастройки, ОписаниеНастройки);
			
			Если ТипЗнч(ЭлементОсновнойНастройки) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
				ОписаниеНастройки = КомпоновщикНастроек.Настройки.ДоступныеПоляОтбораЭлементовСтруктуры.НайтиПоле(ЭлементОсновнойНастройки.ЛевоеЗначение);
				Если ОписаниеНастройки <> Неопределено Тогда
					// @skip-check query-in-loop - запрос к разным таблицам.
					УстановитьДоступныеЗначенияНастроек(Форма, Отчет, КомпоновщикНастроек, ЭлементПользовательскойНастройки, ЭлементОсновнойНастройки, ОписаниеНастройки);
				КонецЕсли;
			КонецЕсли;

		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

Функция ЭтоТехническийОбъект(Знач ПолноеИмяОбъекта) Экспорт
	
	Возврат ПолноеИмяОбъекта = ВРег(Метаданные.Справочники.ПредопределенныеВариантыОтчетовРасширений.ПолноеИмя())
		Или ПолноеИмяОбъекта = ВРег(Метаданные.Справочники.ПредопределенныеВариантыОтчетов.ПолноеИмя());
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

////////////////////////////////////////////////////////////////////////////////
// Настройки варианта

// Определяет свойства параметров вывода, влияющих на отображение заголовка, параметров данных и отборов:
//  * Выводить заголовок;
//  * Заголовок;
//  * Выводить параметры данных;
//  * Выводить отбор;
//
// Параметры:
//  Контекст - Структура - сведения о варианте отчета и о идентификаторе его метаданных.
//  Настройки - НастройкиКомпоновкиДанных - настройки, чьи параметры вывода устанавливаются.
//  Сбросить - Булево - признак того, что параметры вывода необходимо вернуть к исходному состоянию.
//
Процедура ИнициализироватьПредопределенныеПараметрыВывода(Контекст, Настройки, Сбросить = Ложь) Экспорт 
	Если Настройки = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	Если Сбросить Тогда 
		
		СброситьПредопределенныеПараметрыВывода(Настройки);
		Возврат;
		
	КонецЕсли;
	
	ПараметрыВывода = Настройки.ПараметрыВывода.Элементы;
	
	// Параметр Заголовок всегда доступен и только в форме настроек отчета.
	Объект = ПараметрыВывода.Найти("TITLE");
	Объект.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный;
	Объект.ИдентификаторПользовательскойНастройки = "";
	
	УстановитьСтандартныйЗаголовокОтчета(Объект, Контекст);
	
	// Параметр ВыводитьЗаголовок всегда недоступный. Свойства зависят от параметра Заголовок.
	СвязанныйОбъект = ПараметрыВывода.Найти("TITLEOUTPUT");
	СвязанныйОбъект.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
	СвязанныйОбъект.ИдентификаторПользовательскойНастройки = "";
	СвязанныйОбъект.Использование = Истина;
	
	Если Объект.Использование Тогда 
		СвязанныйОбъект.Значение = ТипВыводаТекстаКомпоновкиДанных.Авто;
	Иначе
		СвязанныйОбъект.Значение = ТипВыводаТекстаКомпоновкиДанных.НеВыводить;
	КонецЕсли;
	
	// Параметр ВыводитьПараметры всегда доступен и только в форме настроек отчета.
	Объект = ПараметрыВывода.Найти("DATAPARAMETERSOUTPUT");
	Объект.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный;
	Объект.ИдентификаторПользовательскойНастройки = "";
	Объект.Использование = Истина;
	
	Если Объект.Значение <> ТипВыводаТекстаКомпоновкиДанных.НеВыводить Тогда 
		Объект.Значение = ТипВыводаТекстаКомпоновкиДанных.Авто;
	КонецЕсли;
	
	// Параметр ВыводитьОтбор всегда недоступный. Значения свойств те же, что и у параметра ВыводитьПараметрыДанных.
	СвязанныйОбъект = ПараметрыВывода.Найти("FILTEROUTPUT");
	СвязанныйОбъект.РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
	СвязанныйОбъект.ИдентификаторПользовательскойНастройки = "";
	СвязанныйОбъект.Использование = Истина;
	
	Если СвязанныйОбъект.Значение <> ТипВыводаТекстаКомпоновкиДанных.НеВыводить Тогда 
		СвязанныйОбъект.Значение = ТипВыводаТекстаКомпоновкиДанных.Авто;
	КонецЕсли;
	
	СохранитьСтандартныеЗначенияПредопределенныхПараметровВывода(Настройки);
КонецПроцедуры

Процедура УстановитьСтандартныйЗаголовокОтчета(Заголовок, Контекст)
	Если ЗначениеЗаполнено(Заголовок.Значение) Тогда 
		Возврат;
	КонецЕсли;
	
	ИдентификаторОтчета = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "ОтчетСсылка");
	Если ИдентификаторОтчета = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	ЭтоТипДополнительныйОтчетИлиОбработка = Ложь;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
		МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
		ЭтоТипДополнительныйОтчетИлиОбработка = МодульДополнительныеОтчетыИОбработки.ЭтоТипДополнительныйОтчетИлиОбработка(
			ТипЗнч(ИдентификаторОтчета));
	КонецЕсли;
	
	Если ТипЗнч(ИдентификаторОтчета) = Тип("Строка")
		Или ЭтоТипДополнительныйОтчетИлиОбработка Тогда 
		Заголовок.Значение = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "Наименование", "");
		Возврат;
	КонецЕсли;
	
	Вариант = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Контекст, "ВариантСсылка");
	Если ЗначениеЗаполнено(Вариант) Тогда 
		Заголовок.Значение = Строка(Вариант);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Заголовок.Значение)
		И Заголовок.Значение <> "Основной" Тогда 
		Возврат;
	КонецЕсли;
	
	МетаданныеОтчета = ОбщегоНазначения.ОбъектМетаданныхПоИдентификатору(ИдентификаторОтчета, Ложь);
	Если ТипЗнч(МетаданныеОтчета) = Тип("ОбъектМетаданных") Тогда 
		Заголовок.Значение = МетаданныеОтчета.Представление();
	КонецЕсли;
КонецПроцедуры

Процедура СохранитьСтандартныеЗначенияПредопределенныхПараметровВывода(Настройки)
	
	СтандартныеСвойства = СтандартныеСвойстваПредопределенныхПараметровВывода(Настройки);
	
	Если СтандартныеСвойства <> Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	СтандартныеСвойства = Новый Массив;
	
	ПараметрыВывода = Настройки.ПараметрыВывода.Элементы;
	ИдентификаторыПараметровВывода = СтрРазделить("TITLE, TITLEOUTPUT, DATAPARAMETERSOUTPUT, FILTEROUTPUT", ", ", Ложь);
	
	Для Каждого Идентификатор Из ИдентификаторыПараметровВывода Цикл 
		
		НайденныйПараметр = ПараметрыВывода.Найти(Идентификатор);
		
		Если НайденныйПараметр = Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		
		СвойстваПараметра = СтандартныеСвойстваПредопределенногоПараметраВывода();
		ЗаполнитьЗначенияСвойств(СвойстваПараметра, НайденныйПараметр);
		СвойстваПараметра.Идентификатор =  Идентификатор;
		
		СтандартныеСвойства.Добавить(СвойстваПараметра);
		
	КонецЦикла;
	
	Если СвойстваПараметра.Количество() > 0 Тогда 
		
		Настройки.ДополнительныеСвойства.Вставить(
			КлючСтандартныхСвойствПредопределенныхПараметровВывода(), СтандартныеСвойства);
		
	КонецЕсли;
	
КонецПроцедуры

Процедура СброситьПредопределенныеПараметрыВывода(Настройки)
	
	СтандартныеСвойства = СтандартныеСвойстваПредопределенныхПараметровВывода(Настройки);
	
	Если СтандартныеСвойства = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	ПараметрыВывода = Настройки.ПараметрыВывода.Элементы;
	
	Для Каждого СвойстваПараметра Из СтандартныеСвойства Цикл 
		
		НайденныйПараметр = ПараметрыВывода.Найти(СвойстваПараметра.Идентификатор);
		
		Если НайденныйПараметр = Неопределено Тогда 
			Продолжить;
		КонецЕсли;
		
		ЗаполнитьЗначенияСвойств(НайденныйПараметр, СвойстваПараметра);
		
	КонецЦикла;
	
КонецПроцедуры

Функция ТребуетсяСброситьПредопределенныеПараметрыВывода(ПараметрыЗагрузки) Экспорт 
	
	Если ПараметрыЗагрузки.Свойство("СброситьНастройкиВарианта")
		И ПараметрыЗагрузки.СброситьНастройкиВарианта = Истина Тогда 
		
		Возврат Ложь;
	КонецЕсли;
	
	Если ПараметрыЗагрузки.Свойство("ИмяСобытия")
		И ПараметрыЗагрузки.ИмяСобытия = ОтчетыКлиентСервер.ИмяСобытияНастройкиПоУмолчанию() Тогда 
		
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция КлючСтандартныхСвойствПредопределенныхПараметровВывода()
	
	Возврат "СтандартныеСвойстваПредопределенныхПараметровВывода";
	
КонецФункции

// Параметры:
//  Настройки - НастройкиКомпоновкиДанных
// 
// Возвращаемое значение:
//  - Неопределено
//  - Массив из Структура:
//      * Идентификатор - Строка
//      * Использование - Булево
//      * Значение - Неопределено
//
Функция СтандартныеСвойстваПредопределенныхПараметровВывода(Настройки)
	
	Возврат ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
		Настройки.ДополнительныеСвойства,
		КлючСтандартныхСвойствПредопределенныхПараметровВывода());
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//    * Идентификатор - Строка
//    * Использование - Булево
//    * Значение - Неопределено
//
Функция СтандартныеСвойстваПредопределенногоПараметраВывода()
	
	Возврат Новый Структура("Идентификатор, Использование, Значение", "", Ложь, Неопределено);
	
КонецФункции

Процедура УстановитьФиксированныеОтборы(СтруктураОтборов, НастройкиКД, НастройкиОтчета) Экспорт
	Если ТипЗнч(НастройкиКД) <> Тип("НастройкиКомпоновкиДанных")
		Или СтруктураОтборов = Неопределено
		Или СтруктураОтборов.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;

	ПараметрыКД = НастройкиКД.ПараметрыДанных;
	ОтборыКД = НастройкиКД.Отбор;
	ВидСравненияКД = ВидСравненияКомпоновкиДанных.Равно;
	РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Недоступный;
	Представление = "";
	Идентификатор = "";
	
	Для Каждого КлючИЗначение Из СтруктураОтборов Цикл
		Имя = КлючИЗначение.Ключ;
		
		Если ЭтоОтборОбработчикаРасшифровкиПоДетальнымЗаписям(КлючИЗначение.Значение) Тогда 
			СвойстваОтбора = КлючИЗначение.Значение;
			Значение = СвойстваОтбора.Значение;
			ВидСравненияКД = СвойстваОтбора.ВидСравнения;
			РежимОтображения = СвойстваОтбора.РежимОтображения;
			Представление = СвойстваОтбора.Представление;
			Идентификатор = СвойстваОтбора.ИдентификаторПользовательскойНастройки;
		Иначе
			Значение = КлючИЗначение.Значение;
		КонецЕсли;

		Если ТипЗнч(Значение) = Тип("ФиксированныйМассив") Тогда
			Значение = Новый Массив(Значение);
		КонецЕсли;

		Если ТипЗнч(Значение) = Тип("Массив") Тогда
			Список = Новый СписокЗначений;
			Список.ЗагрузитьЗначения(Значение);
			Значение = Список;
		КонецЕсли;

		ПараметрКД = ПараметрыКД.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных(Имя));

		Если ТипЗнч(ПараметрКД) = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда
			ПараметрКД.ИдентификаторПользовательскойНастройки = Идентификатор;
			ПараметрКД.Использование    = Истина;
			ПараметрКД.РежимОтображения = РежимОтображения;
			ПараметрКД.Значение         = Значение;
			Продолжить;
		КонецЕсли;

		Если ТипЗнч(Значение) = Тип("Структура") Тогда
			ВидСравненияКД = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
				Значение, "ВидСравнения", ВидСравненияКомпоновкиДанных.Равно);
			Значение = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(Значение, "ПравоеЗначение");
		ИначеЕсли ТипЗнч(Значение) = Тип("СписокЗначений") Тогда
			ВидСравненияКД = ВидСравненияКомпоновкиДанных.ВСписке;
		КонецЕсли;
		
		ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбора(
			ОтборыКД, Имя, Значение, ВидСравненияКД, Представление, Истина, РежимОтображения, Идентификатор);
	КонецЦикла;
КонецПроцедуры

Функция ЭтоОтборОбработчикаРасшифровкиПоДетальнымЗаписям(Отбор)
	
	Если ТипЗнч(Отбор) <> Тип("Структура") Тогда 
		Возврат Ложь;
	КонецЕсли;
	
	СвойстваОтбора = ВариантыОтчетовСлужебный.СвойстваОтбораОбработчикаРасшифровкиПоДетальнымЗаписям();
	
	Если Отбор.Количество() <> СвойстваОтбора.Количество() Тогда 
		Возврат Ложь;
	КонецЕсли;
	
	Для Каждого Свойство Из СвойстваОтбора Цикл 
		
		Если Не Отбор.Свойство(Свойство.Ключ) Тогда 
			Возврат Ложь;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

Процедура ЗаполнитьДополнительныеСвойства(ОтчетОбъект, НовыеНастройки, Знач КлючВарианта, Знач КлючПредопределенногоВарианта,
			Знач КонтекстВарианта = "", Знач ФормаПараметрыОтбор = Неопределено) Экспорт
	
	Если ТипЗнч(НовыеНастройки) = Тип("НастройкиКомпоновкиДанных") Тогда
		ЗаполнитьДополнительноеСвойство(НовыеНастройки, "КлючВарианта", КлючВарианта);
		ЗаполнитьДополнительноеСвойство(НовыеНастройки, "КлючПредопределенногоВарианта", КлючПредопределенногоВарианта);
		ЗаполнитьДополнительноеСвойство(НовыеНастройки, "КонтекстВарианта", КонтекстВарианта);
		ЗаполнитьДополнительноеСвойство(НовыеНастройки, "ФормаПараметрыОтбор", ФормаПараметрыОтбор, Новый Структура);
	КонецЕсли;
	
	ТекущиеНастройки = ОтчетОбъект.КомпоновщикНастроек.Настройки;
	ЗаполнитьДополнительноеСвойство(ТекущиеНастройки, "КлючВарианта", КлючВарианта);
	ЗаполнитьДополнительноеСвойство(ТекущиеНастройки, "КлючПредопределенногоВарианта", КлючПредопределенногоВарианта);
	ЗаполнитьДополнительноеСвойство(ТекущиеНастройки, "КонтекстВарианта", КонтекстВарианта);
	ЗаполнитьДополнительноеСвойство(ТекущиеНастройки, "ФормаПараметрыОтбор", ФормаПараметрыОтбор, Новый Структура);
	
КонецПроцедуры

Процедура ЗаполнитьДополнительноеСвойство(Настройки, ИмяСвойства, ЗначениеСвойства, ЗначениеПоУмолчанию = "")
	
	Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда
		Настройки.ДополнительныеСвойства.Вставить(ИмяСвойства, ЗначениеСвойства);
	ИначеЕсли Не Настройки.ДополнительныеСвойства.Свойство(ИмяСвойства, ЗначениеСвойства) Тогда
		Настройки.ДополнительныеСвойства.Вставить(ИмяСвойства, ЗначениеПоУмолчанию);
	КонецЕсли;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Пользовательские настройки

// Собирает статистику по количеству пользовательских настроек в разрезе режимов отображения.
//
// Параметры:
//  КомпоновщикНастроек - КомпоновщикНастроекКомпоновкиДанных - актуальный компоновщик.
//
// Возвращаемое значение:
//   Структура - количество пользовательских настроек в разрезе режимов отображения:
//     * БыстрогоДоступа - Число - количество настроек с режимом отображения БыстрыйДоступ или Авто;
//     * Обычных - Число - количество настроек с режимом отображения Обычный;
//     * Итог - Число - общее количество доступных настроек.
//
Функция КоличествоДоступныхНастроек(КомпоновщикНастроек) Экспорт 
	ДоступныеНастройки = Новый Структура;
	ДоступныеНастройки.Вставить("БыстрогоДоступа", 0);
	ДоступныеНастройки.Вставить("Обычных", 0);
	ДоступныеНастройки.Вставить("Итог", 0);
	
	ПользовательскиеНастройки = КомпоновщикНастроек.ПользовательскиеНастройки;
	Для Каждого ЭлементПользовательскойНастройки Из ПользовательскиеНастройки.Элементы Цикл 
		ЭлементНастройки = ОтчетыКлиентСервер.ПолучитьОбъектПоПользовательскомуИдентификатору(
			КомпоновщикНастроек.Настройки,
			ЭлементПользовательскойНастройки.ИдентификаторПользовательскойНастройки,,
			ПользовательскиеНастройки);
		
		РежимОтображения = ?(ЭлементНастройки = Неопределено,
			ЭлементПользовательскойНастройки.РежимОтображения, ЭлементНастройки.РежимОтображения);
		
		Если РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Авто
			Или РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.БыстрыйДоступ Тогда 
			ДоступныеНастройки.БыстрогоДоступа = ДоступныеНастройки.БыстрогоДоступа + 1;
		ИначеЕсли РежимОтображения = РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный Тогда 
			ДоступныеНастройки.Обычных = ДоступныеНастройки.Обычных + 1;
		КонецЕсли;
	КонецЦикла;
	
	ДоступныеНастройки.Итог = ДоступныеНастройки.БыстрогоДоступа + ДоступныеНастройки.Обычных;
	
	Возврат ДоступныеНастройки;
КонецФункции

Функция СвойстваЭлементаПользовательскихНастроек(КомпоновщикНастроек, ЭлементПользовательскойНастройки, ЭлементНастройки, ОписаниеНастройки)
	Свойства = ПалитраСвойствЭлементаПользовательскихНастроек();
	
	Свойства.ПользовательскаяНастройкаКД = ЭлементПользовательскойНастройки;
	Свойства.ЭлементКД = ЭлементНастройки;
	Свойства.ДоступнаяНастройкаКД = ОписаниеНастройки;
	
	Свойства.Идентификатор = ЭлементПользовательскойНастройки.ИдентификаторПользовательскойНастройки;
	Свойства.ИдентификаторКД = КомпоновщикНастроек.ПользовательскиеНастройки.ПолучитьИдентификаторПоОбъекту(
		ЭлементПользовательскойНастройки);
	Свойства.ИдентификаторЭлемента = СтрЗаменить(
		ЭлементПользовательскойНастройки.ИдентификаторПользовательскойНастройки, "-", "");
	
	ТипЭлементаНастройки = ТипЗнч(ЭлементНастройки);
	Если ТипЭлементаНастройки = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
		Свойства.ПолеКД = Новый ПолеКомпоновкиДанных("ПараметрыДанных." + Строка(ЭлементНастройки.Параметр));
		Свойства.Значение = ЭлементНастройки.Значение;
	ИначеЕсли ТипЗнч(ЭлементНастройки) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда 
		Свойства.ПолеКД = ЭлементНастройки.ЛевоеЗначение;
		Свойства.Значение = ЭлементНастройки.ПравоеЗначение;
	КонецЕсли;
	
	Свойства.Тип = ТипНастройкиСтрокой(ТипЭлементаНастройки);
	
	Если ОписаниеНастройки = Неопределено Тогда 
		Возврат Свойства;
	КонецЕсли;
	
	Свойства.ОписаниеТипов = ОписаниеНастройки.ТипЗначения;
	
	Если ОписаниеНастройки.ДоступныеЗначения <> Неопределено Тогда 
		Свойства.ЗначенияДляВыбора = ОписаниеНастройки.ДоступныеЗначения;
	КонецЕсли;
	
	Возврат Свойства;
КонецФункции

Функция ПалитраСвойствЭлементаПользовательскихНастроек()
	Свойства = Новый Структура;
	Свойства.Вставить("БыстрыйВыбор", Ложь);
	Свойства.Вставить("ВводСписком", Ложь);
	Свойства.Вставить("ВидСравнения", ВидСравненияКомпоновкиДанных.Равно);
	Свойства.Вставить("Владелец", Неопределено);
	Свойства.Вставить("ВыборГруппИЭлементов", ГруппыИЭлементы.Авто);
	Свойства.Вставить("ВыводРазрешен", Истина);
	Свойства.Вставить("ВыводитьВГруппеОсновныхНастроек", Ложь);
	Свойства.Вставить("ВыводитьТолькоФлажок", Ложь);
	Свойства.Вставить("ВыводитьФлажок", Истина);
	Свойства.Вставить("Глобальная", Истина);
	Свойства.Вставить("ДоступнаяНастройкаКД", Неопределено);
	Свойства.Вставить("ЗапросЗначенийВыбора", Новый Запрос);
	Свойства.Вставить("Значение", Неопределено);
	Свойства.Вставить("ЗначенияДляВыбора", Новый СписокЗначений);
	Свойства.Вставить("Идентификатор", "");
	Свойства.Вставить("ИдентификаторКД", Неопределено);
	Свойства.Вставить("ИдентификаторЭлемента", "");
	Свойства.Вставить("ИмяКоллекции", "");
	Свойства.Вставить("ИнформацияОТипах", Новый Структура);
	Свойства.Вставить("ОграничениеТипа", Неопределено);
	Свойства.Вставить("ОграничиватьВыборУказаннымиЗначениями", Ложь);
	Свойства.Вставить("ОписаниеТипов", Новый ОписаниеТипов("Неопределено"));
	Свойства.Вставить("ОтмеченныеЗначения", Неопределено);
	Свойства.Вставить("ПараметрыВыбора", Новый Массив);
	Свойства.Вставить("Подтип", "");
	Свойства.Вставить("ПолеКД", Неопределено);
	Свойства.Вставить("ПользовательскаяНастройка", Неопределено);
	Свойства.Вставить("ПользовательскаяНастройкаКД", Неопределено);
	Свойства.Вставить("Представление", "");
	Свойства.Вставить("ПредставлениеПоУмолчанию", "");
	Свойства.Вставить("Родитель", Неопределено);
	Свойства.Вставить("СвязиПараметровВыбора", Новый Массив);
	Свойства.Вставить("СвязиПоМетаданным", Новый Массив);
	Свойства.Вставить("СвязьПоТипу", Неопределено);
	Свойства.Вставить("СобытиеПриИзменении", Ложь);
	Свойства.Вставить("Состояние", "");
	Свойства.Вставить("СписокЗначенийПереопределен", Ложь);
	Свойства.Вставить("СтрокаДерева", Неопределено);
	Свойства.Вставить("Строки", Неопределено);
	Свойства.Вставить("Тип", "");
	Свойства.Вставить("ФормаВыбора", "");
	Свойства.Вставить("Ширина", 0);
	Свойства.Вставить("ЭлементКД", Неопределено);
	
	Возврат Свойства;
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Вспомогательные

// Создает и возвращает экземпляр отчета по полному имени объекта метаданных.
//
// Параметры:
//  ПолноеИмя - Строка - полное имя объекта метаданных. Пример: "Отчет.БизнесПроцессы".
//
// Возвращаемое значение:
//  ОтчетОбъект - экземпляр отчета.
//
Функция ОтчетОбъект(Идентификатор) Экспорт
	ПолноеИмя = Идентификатор;
	
	Если ТипЗнч(Идентификатор) = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") Тогда
		ПолноеИмя = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Идентификатор, "ПолноеИмя");
	КонецЕсли;
	
	ОписаниеОбъекта = СтрРазделить(ПолноеИмя, ".");
	
	Если ОписаниеОбъекта.Количество() >= 2 Тогда
		Вид = ВРег(ОписаниеОбъекта[0]);
		Имя = ОписаниеОбъекта[1];
	Иначе
		ВызватьИсключение СтрЗаменить(НСтр("ru = 'Некорректное полное имя отчета ""%1"".'"), "%1", ПолноеИмя);
	КонецЕсли;
	
	Если Вид = "ОТЧЕТ" Тогда
		Возврат Отчеты[Имя].Создать();
	ИначеЕсли Вид = "ВНЕШНИЙОТЧЕТ" Тогда
		Возврат ВнешниеОтчеты.Создать(Имя); // АПК:553 Для внешних отчетов, не подключенных к подсистеме "Дополнительные отчеты и обработки". Вызов безопасен, так как проверки безопасности для внешнего отчета выполнены ранее при подключении.
	Иначе
		ВызватьИсключение СтрЗаменить(НСтр("ru = '""%1"" не является отчетом.'"), "%1", ПолноеИмя);
	КонецЕсли;
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обновление элементов формы пользовательских настроек

Процедура ПередОбновлениемЭлементовФормыНастроек(Форма, ПараметрыОбновления)
	
	Если ТипЗнч(ПараметрыОбновления) <> Тип("Структура") Тогда 
		Возврат;
	КонецЕсли;
	
	КомпоновщикНастроек = Форма.Отчет.КомпоновщикНастроек;
	
	ИмяСобытия = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыОбновления, "ИмяСобытия");
	
	Если ИмяСобытия = "НастройкиПоУмолчанию" Тогда 
		КомпоновщикНастроек.Настройки.ДополнительныеСвойства.Вставить("ПорядокЭлементовНастроек", Новый Соответствие);
	КонецЕсли;
	
КонецПроцедуры

// Возвращаемое значение:
//  ТаблицаЗначений:
//    * ИндексНастройки - Число
//    * ИдентификаторНастройки  - Строка
//    * Настройки - НастройкиКомпоновкиДанных
//    * ЭлементНастройки - ЭлементОтбораКомпоновкиДанных
//                       - ЗначениеПараметраНастроекКомпоновкиДанных
//                       - ВыбранноеПолеКомпоновкиДанных
//                       - ЭлементПорядкаКомпоновкиДанных
//                       - ЭлементУсловногоОформления
//    * ОписаниеНастройки - ДоступноеПолеОтбораКомпоновкиДанных
//                        - ДоступныеПараметрыКомпоновкиДанных
//                        - ДоступноеПолеКомпоновкиДанных
//    * Представление - Строка
//    * ИдентификаторГруппы - Строка
//    * ПоложениеЗаголовка - ПоложениеЗаголовкаЭлементаФормы
//    * РастягиватьПоГоризонтали - Булево
//                               - Неопределено
//    * Ширина - Число
//
Функция ПоляЭлементовФормыНастроек()
	
	ОписаниеСтроки = Новый ОписаниеТипов("Строка");
	ОписаниеЧисла = Новый ОписаниеТипов("Число");
	
	Поля = Новый ТаблицаЗначений;
	Поля.Колонки.Добавить("ИндексНастройки", ОписаниеЧисла);
	Поля.Колонки.Добавить("ИдентификаторНастройки", ОписаниеСтроки);
	Поля.Колонки.Добавить("Настройки");
	Поля.Колонки.Добавить("ЭлементНастройки");
	Поля.Колонки.Добавить("ОписаниеНастройки");
	Поля.Колонки.Добавить("Представление", ОписаниеСтроки);
	Поля.Колонки.Добавить("ИдентификаторГруппы", ОписаниеСтроки);
	Поля.Колонки.Добавить("ПоложениеЗаголовка", Новый ОписаниеТипов("ПоложениеЗаголовкаЭлементаФормы"));
	Поля.Колонки.Добавить("РастягиватьПоГоризонтали");
	Поля.Колонки.Добавить("Ширина", ОписаниеЧисла);
	
	Возврат Поля;
	
КонецФункции

// Получение сведений об основных настройках, включенных в состав пользовательских.

// Возвращает проиндексированные свойства пользовательских настроек отчета такие как соответствующие
// элементы основных настроек, дополнительные поля компоновки данных.
// 
// Параметры:
//  Настройки - НастройкиКомпоновкиДанных
// 
// Возвращаемое значение:
//   см. ВидыСведений
//
Функция СведенияОПользовательскихНастройках(Настройки) Экспорт 
	Сведения = Новый Соответствие;
	ПолучитьСведенияОГруппировке(Настройки, Сведения, Настройки.ДополнительныеСвойства);
	
	Возврат Сведения;
КонецФункции

Процедура ПолучитьСведенияОГруппировке(Группировка, Сведения, ДополнительныеСвойства)
	ТипГруппировки = ТипЗнч(Группировка);
	Если ТипГруппировки <> Тип("НастройкиКомпоновкиДанных")
		И ТипГруппировки <> Тип("ГруппировкаКомпоновкиДанных")
		И ТипГруппировки <> Тип("ГруппировкаТаблицыКомпоновкиДанных")
		И ТипГруппировки <> Тип("ГруппировкаДиаграммыКомпоновкиДанных") Тогда 
		Возврат;
	КонецЕсли;
	
	Если ТипГруппировки <> Тип("НастройкиКомпоновкиДанных")
		И ЗначениеЗаполнено(Группировка.ИдентификаторПользовательскойНастройки) Тогда 
		
		ВидыСведений = ВидыСведений();
		ВидыСведений.Настройки = Группировка;
		ВидыСведений.ЭлементНастройки = Группировка;
		
		Сведения.Вставить(Группировка.ИдентификаторПользовательскойНастройки, ВидыСведений);
	КонецЕсли;
	
	ПолучитьСведенияОСвойствахЭлементаНастроек(Группировка, Сведения, ДополнительныеСвойства);
КонецПроцедуры

Процедура ПолучитьСведенияОТаблице(Таблица, Сведения, ДополнительныеСвойства)
	Если ТипЗнч(Таблица) <> Тип("ТаблицаКомпоновкиДанных") Тогда
		Возврат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Таблица.ИдентификаторПользовательскойНастройки) Тогда 
		ВидыСведений = ВидыСведений();
		ВидыСведений.Настройки = Таблица;
		ВидыСведений.ЭлементНастройки = Таблица;
		
		Сведения.Вставить(Таблица.ИдентификаторПользовательскойНастройки, ВидыСведений);
	КонецЕсли;
	
	ПолучитьСведенияОСвойствахЭлементаНастроек(Таблица, Сведения, ДополнительныеСвойства);
	ПолучитьСведенияОКоллекции(Таблица, Таблица.Строки, Сведения, ДополнительныеСвойства);
	ПолучитьСведенияОКоллекции(Таблица, Таблица.Колонки, Сведения, ДополнительныеСвойства);
КонецПроцедуры

Процедура ПолучитьСведенияОДиаграмме(Диаграмма, Сведения, ДополнительныеСвойства)
	Если ТипЗнч(Диаграмма) <> Тип("ДиаграммаКомпоновкиДанных") Тогда
		Возврат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Диаграмма.ИдентификаторПользовательскойНастройки) Тогда 
		ВидыСведений = ВидыСведений();
		ВидыСведений.Настройки = Диаграмма;
		ВидыСведений.ЭлементНастройки = Диаграмма;
		
		Сведения.Вставить(Диаграмма.ИдентификаторПользовательскойНастройки, ВидыСведений);
	КонецЕсли;
	
	ПолучитьСведенияОСвойствахЭлементаНастроек(Диаграмма, Сведения, ДополнительныеСвойства);
	ПолучитьСведенияОКоллекции(Диаграмма, Диаграмма.Серии, Сведения, ДополнительныеСвойства);
	ПолучитьСведенияОКоллекции(Диаграмма, Диаграмма.Точки, Сведения, ДополнительныеСвойства);
КонецПроцедуры

Процедура ПолучитьСведенияОКоллекции(ЭлементНастроек, Коллекция, Сведения, ДополнительныеСвойства)
	ТипКоллекции = ТипЗнч(Коллекция);
	Если ТипКоллекции <> Тип("КоллекцияЭлементовСтруктурыТаблицыКомпоновкиДанных")
		И ТипКоллекции <> Тип("КоллекцияЭлементовСтруктурыДиаграммыКомпоновкиДанных")
		И ТипКоллекции <> Тип("КоллекцияЭлементовСтруктурыНастроекКомпоновкиДанных") Тогда
		Возврат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Коллекция.ИдентификаторПользовательскойНастройки) Тогда 
		ВидыСведений = ВидыСведений();
		ВидыСведений.Настройки = ЭлементНастроек;
		ВидыСведений.ЭлементНастройки = Коллекция;
		
		Сведения.Вставить(Коллекция.ИдентификаторПользовательскойНастройки, ВидыСведений);
	КонецЕсли;
	
	Для Каждого Элемент Из Коллекция Цикл 
		Настройки = Элемент;
		Если ТипЗнч(Элемент) = Тип("НастройкиВложенногоОбъектаКомпоновкиДанных") Тогда
			Если ЗначениеЗаполнено(Элемент.ИдентификаторПользовательскойНастройки) Тогда 
				ВидыСведений = ВидыСведений();
				ВидыСведений.Настройки = Элемент;
				ВидыСведений.ЭлементНастройки = Элемент;
				
				Сведения.Вставить(Элемент.ИдентификаторПользовательскойНастройки, ВидыСведений);
			КонецЕсли;
			
			Настройки = Элемент.Настройки;
		КонецЕсли;

		ПолучитьСведенияОГруппировке(Настройки, Сведения, ДополнительныеСвойства);
		ПолучитьСведенияОТаблице(Настройки, Сведения, ДополнительныеСвойства);
		ПолучитьСведенияОДиаграмме(Настройки, Сведения, ДополнительныеСвойства);
	КонецЦикла;
КонецПроцедуры

Процедура ПолучитьСведенияОСвойствахЭлементаНастроек(ЭлементНастроек, Сведения, ДополнительныеСвойства)
	ИдентификаторыСвойств = ИдентификаторыСвойствНастроек(ДополнительныеСвойства);
	ДополнительныеИдентификаторы = Новый Массив;
	
	ДоступныеСвойства = Новый Структура("Выбор, Отбор, Порядок, УсловноеОформление, Структура");
	
	ТипЭлементаНастроек = ТипЗнч(ЭлементНастроек);
	Если ТипЭлементаНастроек <> Тип("ТаблицаКомпоновкиДанных")
		И ТипЭлементаНастроек <> Тип("ДиаграммаКомпоновкиДанных") Тогда 
		
		ДополнительныеИдентификаторы.Добавить("Отбор");
		ДополнительныеИдентификаторы.Добавить("Порядок");
		ДополнительныеИдентификаторы.Добавить("Структура");
		
		Если ТипЭлементаНастроек = Тип("НастройкиКомпоновкиДанных") Тогда 
			ДополнительныеИдентификаторы.Добавить("ПараметрыДанных");
		КонецЕсли;
	КонецЕсли;
	
	ОбщегоНазначенияКлиентСервер.ДополнитьМассив(ИдентификаторыСвойств, ДополнительныеИдентификаторы, Истина);
	
	Для Каждого Идентификатор Из ИдентификаторыСвойств Цикл 
		Свойство = ЭлементНастроек[Идентификатор];
		
		Если ДоступныеСвойства.Свойство(Идентификатор)
			И ЗначениеЗаполнено(Свойство.ИдентификаторПользовательскойНастройки) Тогда 
			
			ВидыСведений = ВидыСведений();
			ВидыСведений.Настройки = ЭлементНастроек;
			ВидыСведений.ЭлементНастройки = Свойство;
			
			Сведения.Вставить(Свойство.ИдентификаторПользовательскойНастройки, ВидыСведений);
		КонецЕсли;
		
		ПолучитьСведенияОЭлементахСвойстваНастроек(ЭлементНастроек, Свойство, Идентификатор, Сведения, ДополнительныеСвойства);
		ПолучитьСведенияОКоллекции(ЭлементНастроек, Свойство, Сведения, ДополнительныеСвойства);
	КонецЦикла;
КонецПроцедуры

// Добавляет сведения о элементах отборов, значениях параметров и т.д.
// 
// Параметры:
//   Настройки - НастройкиКомпоновкиДанных
//   Свойство - ОтборКомпоновкиДанных
//            - ЗначенияПараметровДанныхКомпоновкиДанных
//            - ЗначенияПараметровВыводаКомпоновкиДанных
//            - УсловноеОформлениеКомпоновкиДанных
//   ИдентификаторСвойства - Строка
//   Сведения - см. ВидыСведений
//   ДополнительныеСвойства - Структура
//
Процедура ПолучитьСведенияОЭлементахСвойстваНастроек(Настройки, Свойство, ИдентификаторСвойства, Сведения, ДополнительныеСвойства)
	СвойстваСЭлементами = Новый Структура("Отбор, ПараметрыДанных, ПараметрыВывода, УсловноеОформление");
	Если Не СвойстваСЭлементами.Свойство(ИдентификаторСвойства) Тогда 
		Возврат;
	КонецЕсли;
	
	Для Каждого Элемент Из Свойство.Элементы Цикл 
		ТипЭлемента = ТипЗнч(Элемент);
		
		Если ЗначениеЗаполнено(Элемент.ИдентификаторПользовательскойНастройки) Тогда 
			Описание = Неопределено;
			Если ТипЭлемента = Тип("ЭлементОтбораКомпоновкиДанных") Тогда 
				
				ДоступныеПоля = Настройки[ИдентификаторСвойства].ДоступныеПоляОтбора;
				Если ДоступныеПоля <> Неопределено Тогда 
					Описание = ДоступныеПоля.НайтиПоле(Элемент.ЛевоеЗначение);
				КонецЕсли;
				
			ИначеЕсли ТипЭлемента = Тип("ЗначениеПараметраКомпоновкиДанных")
				Или ТипЭлемента = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
				
				ДоступныеПараметры = Настройки[ИдентификаторСвойства].ДоступныеПараметры;
				Если ДоступныеПараметры <> Неопределено Тогда 
					Описание = ДоступныеПараметры.НайтиПараметр(Элемент.Параметр);
				КонецЕсли;
			КонецЕсли;
			
			ВидыСведений = ВидыСведений();
			ВидыСведений.Настройки = Настройки;
			ВидыСведений.ЭлементНастройки = Элемент;
			ВидыСведений.ОписаниеНастройки = Описание;
			
			Сведения.Вставить(Элемент.ИдентификаторПользовательскойНастройки, ВидыСведений);
		КонецЕсли;
		
		Если ТипЭлемента = Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда 
			ПолучитьСведенияОЭлементахСвойстваНастроек(
				Настройки, Элемент, ИдентификаторСвойства, Сведения, ДополнительныеСвойства);
		ИначеЕсли ТипЭлемента = Тип("ЗначениеПараметраКомпоновкиДанных")
			Или ТипЭлемента = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
			ПолучитьСведенияОЗначенияхВложенныхПараметров(
				Настройки, Элемент.ЗначенияВложенныхПараметров, ИдентификаторСвойства, Сведения, ДополнительныеСвойства);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

Процедура ПолучитьСведенияОЗначенияхВложенныхПараметров(Настройки, ЗначенияПараметров, ИдентификаторСвойства, Сведения, ДополнительныеСвойства)
	Для Каждого ЗначениеПараметра Из ЗначенияПараметров Цикл 
		Если ЗначениеЗаполнено(ЗначениеПараметра.ИдентификаторПользовательскойНастройки) Тогда 
			ВидыСведений = ВидыСведений();
			ВидыСведений.Настройки = Настройки;
			ВидыСведений.ЭлементНастройки = ЗначениеПараметра;
			ВидыСведений.ОписаниеНастройки =
				Настройки[ИдентификаторСвойства].ДоступныеПараметры.НайтиПараметр(ЗначениеПараметра.Параметр);
			
			Сведения.Вставить(ЗначениеПараметра.ИдентификаторПользовательскойНастройки, ВидыСведений);
		КонецЕсли;
		
		ПолучитьСведенияОЗначенияхВложенныхПараметров(
			Настройки, ЗначениеПараметра.ЗначенияВложенныхПараметров, ИдентификаторСвойства, Сведения, ДополнительныеСвойства);
	КонецЦикла;
КонецПроцедуры

Функция ИдентификаторыСвойствНастроек(ДополнительныеСвойства)
	ИдентификаторыСвойствПоУмолчанию = СтрРазделить("Выбор, ПараметрыВывода, УсловноеОформление", ", ", Ложь);
	
	ИдентификаторыСвойств = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
		ДополнительныеСвойства,
		"ИдентификаторыСвойствНастроек",
		ИдентификаторыСвойствПоУмолчанию);
	
	Возврат ОбщегоНазначения.СкопироватьРекурсивно(ИдентификаторыСвойств);
КонецФункции

// Конструктор индекса свойств пользовательских настроек.
// 
// Возвращаемое значение:
//   Структура:
//   * Настройки - НастройкиКомпоновкиДанных
//   * ЭлементНастройки - ЭлементОтбораКомпоновкиДанных
//                    - ЗначениеПараметраКомпоновкиДанных
//                    - ВыбранноеПолеКомпоновкиДанных
//   * ОписаниеНастройки - ДоступноеПолеОтбораКомпоновкиДанных
//                     - ДоступныйПараметрКомпоновкиДанных
//
Функция ВидыСведений()
	Возврат Новый Структура("Настройки, ЭлементНастройки, ОписаниеНастройки");
КонецФункции

// Перегруппировка элементов формы, связанных с пользовательскими настройками.

// Формирует коллекции имен реквизитов, сгруппированных по стилям: Период, Флажок, Список.
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//         - РасширениеУправляемойФормыДляОтчета
//   ВидыЭлементов - Массив из Строка
//
// Возвращаемое значение:
//   Структура:
//     * Сгенерированных - Структура
//     * Предопределенных - Структура
//
Функция ИменаРеквизитовЭлементовНастроек(Форма, ВидыЭлементов)
	ИменаРеквизитовПредопределенных = Новый Структура;
	ИменаРеквизитовСгенерированных = Новый Структура;
	
	Для Каждого ВидЭлемента Из ВидыЭлементов Цикл 
		ИменаРеквизитовПредопределенных.Вставить(ВидЭлемента, Новый Массив);
		ИменаРеквизитовСгенерированных.Вставить(ВидЭлемента, Новый Массив);
	КонецЦикла;
	
	Реквизиты = Форма.ПолучитьРеквизиты();
	Для Каждого Реквизит Из Реквизиты Цикл 
		Для Каждого ВидЭлемента Из ВидыЭлементов Цикл 
			Если СтрНачинаетсяС(Реквизит.Имя, ВидЭлемента)
				И СтроковыеФункцииКлиентСервер.ТолькоЦифрыВСтроке(СтрЗаменить(Реквизит.Имя, ВидЭлемента, "")) Тогда
				
				ИменаРеквизитовПоВидам = ИменаРеквизитовПредопределенных[ВидЭлемента]; // Массив из Строка
				ИменаРеквизитовПоВидам.Добавить(Реквизит.Имя);
			КонецЕсли;
			
			Если СтрНачинаетсяС(Реквизит.Имя, "КомпоновщикНастроекПользовательскиеНастройкиЭлемент")
				И СтрЗаканчиваетсяНа(Реквизит.Имя, ВидЭлемента) Тогда 
				
				ИменаРеквизитовПоВидам = ИменаРеквизитовСгенерированных[ВидЭлемента]; // Массив из Строка
				ИменаРеквизитовПоВидам.Добавить(Реквизит.Имя);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	ИменаРеквизитов = Новый Структура;
	ИменаРеквизитов.Вставить("Предопределенных", ИменаРеквизитовПредопределенных);
	ИменаРеквизитов.Вставить("Сгенерированных", ИменаРеквизитовСгенерированных);
	
	Возврат ИменаРеквизитов;
КонецФункции

Процедура ПодготовитьФормуКПерегруппировкеЭлементов(Форма, УзелИерархииЭлементов, ИменаРеквизитов, ВидыСтилизованныхЭлементов)
	Элементы = Форма.Элементы;
	
	// Перегруппировка предопределенных элементов формы.
	СвойстваПредопределенныхЭлементов = СтрРазделить("Отступ, Подбор, ВставитьИзБуфера", ", ", Ложь);
	СвойстваПредопределенныхЭлементов.Добавить("");
	
	Для Каждого ВидЭлемента Из ВидыСтилизованныхЭлементов Цикл 
		ИменаПредопределенныхРеквизитов = ИменаРеквизитов.Предопределенных[ВидЭлемента];
		Для Каждого ИмяРеквизита Из ИменаПредопределенныхРеквизитов Цикл 
			Для Каждого Свойство Из СвойстваПредопределенныхЭлементов Цикл 
				НайденныйЭлемент = Элементы.Найти(ИмяРеквизита + Свойство);
				Если НайденныйЭлемент <> Неопределено Тогда 
					Элементы.Переместить(НайденныйЭлемент, Элементы.ПредопределенныеЭлементыНастроек);
					НайденныйЭлемент.Видимость = Ложь;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	// Удаление динамических элементов формы.
	УзлыИерархииЭлементов = Новый Массив;
	УзлыИерархииЭлементов.Добавить(УзелИерархииЭлементов);
	
	НайденныйУзел = Элементы.Найти("Дополнительно");
	Если НайденныйУзел <> Неопределено Тогда 
		УзлыИерархииЭлементов.Добавить(НайденныйУзел);
	КонецЕсли;
	
	Исключения = Новый Массив;
	
	НайденныйУзел = Элементы.Найти("ПредопределенныеНастройки");
	Если НайденныйУзел <> Неопределено Тогда 
		Исключения.Добавить(НайденныйУзел);
	КонецЕсли;
	
	Для Каждого ТекущийУзел Из УзлыИерархииЭлементов Цикл 
		ИерархияЭлементов = ТекущийУзел.ПодчиненныеЭлементы;
		ИндексЭлемента = ИерархияЭлементов.Количество() - 1;
		Пока ИндексЭлемента >= 0 Цикл 
			ЭлементИерархии = ИерархияЭлементов[ИндексЭлемента];
			Если Исключения.Найти(ЭлементИерархии) = Неопределено Тогда 
				Элементы.Удалить(ЭлементИерархии);
			КонецЕсли;
			ИндексЭлемента = ИндексЭлемента - 1;
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

Процедура ПерегруппироватьЭлементыФормыНастроек(Форма, Знач УзелИерархииЭлементов, СвойстваЭлементов, ИменаРеквизитов, ВидыСтилизованныхЭлементов)
	ОписаниеНастроек = СвойстваЭлементов.Поля.Скопировать(,
		"ИндексНастройки, ИдентификаторНастройки, Настройки, ЭлементНастройки, ОписаниеНастройки");
	
	ЭлементыНастроек = ЭлементыФормыНастроек(Форма, ОписаниеНастроек, ИменаРеквизитов);
	УстановитьСвойстваЭлементовФормыНастроек(Форма, ЭлементыНастроек, СвойстваЭлементов);
	
	Если Форма.ТипФормыОтчета <> ТипФормыОтчета.Настройка Тогда 
		ЭлементыНастроек.ЗаполнитьЗначения(Ложь, "ЭтоСписок");
	КонецЕсли;
	
	ВынестиСписокВОтдельнуюГруппу(ЭлементыНастроек, СвойстваЭлементов);
	
	ИдентификаторыГрупп = СвойстваЭлементов.Поля.Скопировать();
	ИдентификаторыГрупп.Свернуть("ИдентификаторГруппы");
	ИдентификаторыГрупп = ИдентификаторыГрупп.ВыгрузитьКолонку("ИдентификаторГруппы");
	
	Элементы = Форма.Элементы;
	
	Если ИдентификаторыГрупп.Количество() = 1 Тогда 
		УзелИерархииЭлементов.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	Иначе
		УзелИерархииЭлементов.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
	КонецЕсли;
	
	НомерГруппы = 0;
	Для Каждого ИдентификаторГруппы Из ИдентификаторыГрупп Цикл 
		НомерГруппы = НомерГруппы + 1;
		
		СвойстваГруппы = Неопределено;
		Если Не ЗначениеЗаполнено(ИдентификаторГруппы)
			Или Не СвойстваЭлементов.Группы.Свойство(ИдентификаторГруппы, СвойстваГруппы) Тогда 
			СвойстваГруппы = СвойстваГруппыЭлементовФормы();
		КонецЕсли;
		
		НайденныйУзелИерархии = Элементы.Найти(ИдентификаторГруппы);
		Если НайденныйУзелИерархии <> Неопределено Тогда 
			УзелИерархииЭлементов = НайденныйУзелИерархии;
			НомерГруппы = 1;
		КонецЕсли;
		
		ИмяГруппы = УзелИерархииЭлементов.Имя + "Строка" + НомерГруппы;
		Группа = Элементы.Найти(ИмяГруппы);
		
		Если Группа = Неопределено Тогда 
			Группа = ГруппаЭлементовФормыНастроек(Форма, УзелИерархииЭлементов, ИмяГруппы);
			Группа.Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Строка %1'"), НомерГруппы);
		КонецЕсли;
		
		ЗаполнитьЗначенияСвойств(Группа, СвойстваГруппы,, "Группировка, Заголовок");
		Группа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
		УточнитьСвойстваГруппыУзлаИерархииЭлементовФормыНастроек(Группа, СвойстваГруппы);
		
		ПоискПолейГруппы = Новый Структура("ИдентификаторГруппы", ИдентификаторГруппы);
		СвойстваПолейГруппы = СвойстваЭлементов.Поля.НайтиСтроки(ПоискПолейГруппы);
		ЭлементыНастроекГруппы = ЭлементыНастроекГруппы(ЭлементыНастроек, СвойстваПолейГруппы);
		
		ДополнительныеСвойства = Форма.Отчет.КомпоновщикНастроек.Настройки.ДополнительныеСвойства;
		ПодготовитьЭлементыФормыНастроекКРаспределению(
			ЭлементыНастроекГруппы, СвойстваГруппы.Группировка, ЭтоОсновнаяФорма(Форма), ДополнительныеСвойства);
		
		РаспределитьЭлементыФормыНастроек(Форма, Группа, ЭлементыНастроекГруппы);
	КонецЦикла;
	
	УточнитьСвойстваГруппУзлаИерархииЭлементовФормыНастроек(УзелИерархииЭлементов);
	
	ВывестиСтилизованныеЭлементыФормыНастроек(Форма, ЭлементыНастроек, ОписаниеНастроек, ИменаРеквизитов, ВидыСтилизованныхЭлементов);
	ДобавитьОтступКолонок(Форма, ЭлементыНастроек, УзелИерархииЭлементов);
КонецПроцедуры

Процедура УточнитьСвойстваГруппыУзлаИерархииЭлементовФормыНастроек(Группа, СвойстваГруппы)
	
	ЗаголовокГруппы = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(СвойстваГруппы, "Заголовок", "");
	
	Если ЗначениеЗаполнено(ЗаголовокГруппы) Тогда 
		Группа.Заголовок = ЗаголовокГруппы;
	КонецЕсли;
	
	Если Группа.Поведение = ПоведениеОбычнойГруппы.Обычное Тогда 
		Возврат;
	КонецЕсли;
	
	Группа.ОтображатьЗаголовок = Истина;
	
	ГруппаСвернута = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(СвойстваГруппы, "Свернута", Ложь);
	
	Если ГруппаСвернута Тогда 
		Группа.Скрыть();
	Иначе
		Группа.Показать();
	КонецЕсли;
	
КонецПроцедуры

Процедура УточнитьСвойстваГруппУзлаИерархииЭлементовФормыНастроек(УзелИерархииЭлементов)
	
	ПоведениеПереопределено = ПоведениеГруппУзлаИерархииЭлементовФормыНастроекПереопределено(УзелИерархииЭлементов);
	
	Если Не ПоведениеПереопределено Тогда 
		Возврат;
	КонецЕсли;
	
	Для Каждого Группа Из УзелИерархииЭлементов.ПодчиненныеЭлементы Цикл 
		Группа.Объединенная = Истина;
	КонецЦикла;
	
КонецПроцедуры

Функция ПоведениеГруппУзлаИерархииЭлементовФормыНастроекПереопределено(УзелИерархииЭлементов)
	
	Для Каждого Группа Из УзелИерархииЭлементов.ПодчиненныеЭлементы Цикл 
		
		Если ЗначениеЗаполнено(Группа.Подсказка)
			Или ЗначениеЗаполнено(Группа.Высота)
			Или ЗначениеЗаполнено(Группа.Ширина)
			Или Группа.РастягиватьПоВертикали <> Неопределено
			Или Группа.РастягиватьПоГоризонтали <> Неопределено
			Или Группа.Поведение <> ПоведениеОбычнойГруппы.Обычное Тогда 
			
			Возврат Истина;
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

Процедура ДобавитьОтступКолонок(Форма, ЭлементыНастроек, УзелИерархииЭлементов)
	
	Если Не ЭтоОсновнаяФорма(Форма) Тогда 
		Возврат;
	КонецЕсли;
	
	НастройкиОтчета = Форма.НастройкиОтчета;
	
	Если НастройкиОтчета.События.ПриОпределенииСвойствЭлементовФормыНастроек Тогда 
		Возврат;
	КонецЕсли;
	
	Элементы = Форма.Элементы;
	
	Статистика = ЭлементыНастроек.Скопировать();
	Статистика.Свернуть("ИндексНастройки");
	
	Если Статистика.Количество() < 2 Тогда 
		Возврат;
	КонецЕсли;
	
	ПодчиненныеЭлементы = УзелИерархииЭлементов.ПодчиненныеЭлементы;
	КоличествоКолонок = ПодчиненныеЭлементы.Количество();
	
	Для НомерКолонки = 2 По КоличествоКолонок Цикл 
		
		Колонка = ПодчиненныеЭлементы[НомерКолонки - 1];
		
		ИмяГруппы = УзелИерархииЭлементов.Имя + "ПоляКолонки" + НомерКолонки;
		ГруппаПолейКолонки = ГруппаЭлементовФормыНастроек(Форма, УзелИерархииЭлементов, ИмяГруппы);
		
		ГруппаПолейКолонки.Группировка = Колонка.Группировка;
		ГруппаПолейКолонки.Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Поля колонки %1'"), НомерКолонки);
		
		ПоляКолонки = Колонка.ПодчиненныеЭлементы;
		КоличествоПолейКолонки = ПоляКолонки.Количество();
		
		Для НомерПоля = 1 По КоличествоПолейКолонки Цикл 
			Элементы.Переместить(ПоляКолонки[0], ГруппаПолейКолонки);
		КонецЦикла;
		
		Колонка.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
		
		ИмяОтступа = УзелИерархииЭлементов.Имя + "ОтступПолейКолонки" + НомерКолонки;
		Отступ = Элементы.Добавить(ИмяОтступа, Тип("ДекорацияФормы"), Колонка);
		Отступ.Заголовок = "  ";
		
		Элементы.Переместить(ГруппаПолейКолонки, Колонка);
		
	КонецЦикла;
	
КонецПроцедуры

// Поиск созданных системой элементов формы настроек и их подготовка к распределению

Функция ЭлементыФормыНастроек(Форма, ОписаниеНастроек, ИменаРеквизитов)
	Элементы = Форма.Элементы;
	
	ЭлементыНастроек = ПалитраКоллекцииЭлементовНастроек();
	НайтиЭлементыФормыНастроек(Форма, Элементы.Временная, ЭлементыНастроек, ОписаниеНастроек);
	УдалитьЭлементыЗначенийФлажков(ЭлементыНастроек);
	
	СводныеСведения = ЭлементыНастроек.Скопировать();
	СводныеСведения.Свернуть("ИндексНастройки", "КонтрольнаяСумма");
	НеполныеЭлементы = СводныеСведения.НайтиСтроки(Новый Структура("КонтрольнаяСумма", 1));
	
	Поиск = Новый Структура("ИндексНастройки, СвойствоНастройки");
	ОбщиеСвойства = "ЭтоПериод, ЭтоФлажок, ЭтоСписок, ТипЗначения, ФормаВыбора, ДоступныеЗначения, ИдентификаторНастройки";
	
	Для Каждого Запись Из НеполныеЭлементы Цикл 
		Элемент = ЭлементыНастроек.Найти(Запись.ИндексНастройки, "ИндексНастройки");
		Элемент.Поле.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
		
		ИсходноеСвойство = "Значение";
		СвязанноеСвойство = "Использование";
		Если СтрЗаканчиваетсяНа(Элемент.Поле.Имя, СвязанноеСвойство) Тогда 
			ИсходноеСвойство = "Использование";
			СвязанноеСвойство = "Значение";
		КонецЕсли;
		
		ИмяДополнительногоЭлемента = СтрЗаменить(Элемент.Поле.Имя, Элемент.СвойствоНастройки, СвязанноеСвойство);
		
		ГруппаЭлемента = Элемент.Поле.Родитель;
		Если Элементы.Найти(ИмяДополнительногоЭлемента) <> Неопределено
			Или ГруппаЭлемента.ПодчиненныеЭлементы.Найти(ИмяДополнительногоЭлемента) <> Неопределено Тогда 
			
			Если Элемент.ЭтоФлажок Тогда 
				ИмяДополнительногоЭлемента = ИмяДополнительногоЭлемента + "Дополнительное";
			Иначе
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		ДополнительныйЭлемент = Элементы.Добавить(ИмяДополнительногоЭлемента, Тип("ДекорацияФормы"), ГруппаЭлемента);
		ДополнительныйЭлемент.Заголовок = Элемент.Поле.Заголовок;
		ДополнительныйЭлемент.АвтоМаксимальнаяВысота = Ложь;
		
		ДополнительнаяЗапись = ЭлементыНастроек.Добавить();
		ДополнительнаяЗапись.Поле = ДополнительныйЭлемент;
		ДополнительнаяЗапись.ИндексНастройки = Запись.ИндексНастройки;
		ДополнительнаяЗапись.СвойствоНастройки = СвязанноеСвойство;
		ДополнительнаяЗапись.КонтрольнаяСумма = 1;
		
		Поиск.ИндексНастройки = Запись.ИндексНастройки;
		Поиск.СвойствоНастройки = ИсходноеСвойство;
		СвязанныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
		ЗаполнитьЗначенияСвойств(ДополнительнаяЗапись, СвязанныеЭлементы[0], ОбщиеСвойства);
	КонецЦикла;
	
	НайтиЗначенияКакФлажки(Форма, ЭлементыНастроек, ИменаРеквизитов);
	
	ЭлементыНастроек.Сортировать("ИндексНастройки");
	
	Возврат ЭлементыНастроек;
КонецФункции

Функция ПалитраКоллекцииЭлементовНастроек()
	ОписаниеЧисла = Новый ОписаниеТипов("Число");
	ОписаниеСтроки = Новый ОписаниеТипов("Строка");
	ОписаниеПризнака = Новый ОписаниеТипов("Булево");
	
	ЭлементыНастроек = Новый ТаблицаЗначений;
	ЭлементыНастроек.Колонки.Добавить("Порядок", ОписаниеЧисла);
	ЭлементыНастроек.Колонки.Добавить("ИндексНастройки", ОписаниеЧисла);
	ЭлементыНастроек.Колонки.Добавить("СвойствоНастройки", ОписаниеСтроки);
	ЭлементыНастроек.Колонки.Добавить("Поле");
	ЭлементыНастроек.Колонки.Добавить("ИдентификаторНастройки", ОписаниеСтроки);
	ЭлементыНастроек.Колонки.Добавить("ЭтоПериод", ОписаниеПризнака);
	ЭлементыНастроек.Колонки.Добавить("ЭтоСписок", ОписаниеПризнака);
	ЭлементыНастроек.Колонки.Добавить("ЭтоФлажок", ОписаниеПризнака);
	ЭлементыНастроек.Колонки.Добавить("ЭтоЗначениеКакФлажок", ОписаниеПризнака);
	ЭлементыНастроек.Колонки.Добавить("ТипЗначения");
	ЭлементыНастроек.Колонки.Добавить("ФормаВыбора", ОписаниеСтроки);
	ЭлементыНастроек.Колонки.Добавить("ДоступныеЗначения");
	ЭлементыНастроек.Колонки.Добавить("КонтрольнаяСумма", ОписаниеЧисла);
	ЭлементыНастроек.Колонки.Добавить("НомерКолонки", ОписаниеЧисла);
	ЭлементыНастроек.Колонки.Добавить("НомерГруппы", ОписаниеЧисла);
	
	Возврат ЭлементыНастроек;
КонецФункции

// Выполняет поиск элементов формы, связанных с пользовательскими настройками отчета,
// созданных методом СоздатьЭлементыФормыПользовательскихНастроек.
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//         - РасширениеУправляемойФормыДляОтчета:
//     * Элементы - ВсеЭлементыФормы
//     * Отчет - ОтчетОбъект
//   ГруппаЭлементов - ГруппаФормы
//   ЭлементыНастроек - см. ПалитраКоллекцииЭлементовНастроек
//   ОписаниеНастроек - ТаблицаЗначений
//
Процедура НайтиЭлементыФормыНастроек(Форма, ГруппаЭлементов, ЭлементыНастроек, ОписаниеНастроек)
	ПользовательскиеНастройки = Форма.Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы;
	
	ОсновныеСвойства = Новый Структура("Использование, Значение");
	Для Каждого Элемент Из ГруппаЭлементов.ПодчиненныеЭлементы Цикл 
		Если ТипЗнч(Элемент) = Тип("ГруппаФормы") Тогда 
			НайтиЭлементыФормыНастроек(Форма, Элемент, ЭлементыНастроек, ОписаниеНастроек);
		ИначеЕсли ТипЗнч(Элемент) = Тип("ПолеФормы") Тогда 
			СвойствоНастройки = Неопределено;
			ИндексНастройки = ОтчетыКлиентСервер.ИндексЭлементаНастройкиПоПути(Элемент.Имя, СвойствоНастройки);
			
			ОписаниеНастройкиЭлемента = ОписаниеНастроек.Найти(ИндексНастройки, "ИндексНастройки");
			Если ОписаниеНастройкиЭлемента = Неопределено Тогда 
				Продолжить;
			КонецЕсли;
			
			Запись = ЭлементыНастроек.Добавить();
			Запись.ИндексНастройки = ИндексНастройки;
			Запись.СвойствоНастройки = СвойствоНастройки;
			Запись.Поле = Элемент;
			Запись.ИдентификаторНастройки = ОписаниеНастройкиЭлемента.ИдентификаторНастройки;
			
			ЭлементНастройки = ОписаниеНастройкиЭлемента.ЭлементНастройки;
			ОписаниеНастройки = ОписаниеНастройкиЭлемента.ОписаниеНастройки;
			
			Если ОписаниеНастройки <> Неопределено Тогда 
				ЗаполнитьЗначенияСвойств(Запись, ОписаниеНастройки, "ТипЗначения, ФормаВыбора, ДоступныеЗначения");
			КонецЕсли;
			
			Если ТипЗнч(ЭлементНастройки) = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
				Запись.ЭтоПериод = ТипЗнч(ЭлементНастройки.Значение) = Тип("СтандартныйПериод");
				Запись.ЭтоСписок = ОписаниеНастройки <> Неопределено И ОписаниеНастройки.ДоступенСписокЗначений;
			ИначеЕсли ТипЗнч(ЭлементНастройки) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда 
				Запись.ЭтоПериод = ТипЗнч(ЭлементНастройки.ПравоеЗначение) = Тип("СтандартныйПериод");
				Запись.ЭтоФлажок = ЗначениеЗаполнено(ЭлементНастройки.Представление)
					Или ЭлементНастройки.ВидСравнения = ВидСравненияКомпоновкиДанных.Заполнено
					Или ЭлементНастройки.ВидСравнения = ВидСравненияКомпоновкиДанных.НеЗаполнено;
				
				ЭлементПользовательскойНастройки = ПользовательскиеНастройки.Найти(
					ОписаниеНастройкиЭлемента.ИдентификаторНастройки);
				
				Запись.ЭтоСписок = Не Запись.ЭтоФлажок
					И ОтчетыКлиентСервер.ЭтоВидСравненияСписка(ЭлементПользовательскойНастройки.ВидСравнения);
			ИначеЕсли ТипЗнч(ЭлементНастройки) = Тип("ЭлементУсловногоОформленияКомпоновкиДанных") Тогда 
				Запись.ЭтоФлажок = ЗначениеЗаполнено(ЭлементНастройки.Представление)
					Или ЗначениеЗаполнено(ЭлементНастройки.ПредставлениеПользовательскойНастройки);
			КонецЕсли;
			
			Если ОсновныеСвойства.Свойство(Запись.СвойствоНастройки) Тогда 
				Запись.КонтрольнаяСумма = 1;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

Процедура УдалитьЭлементыЗначенийФлажков(ЭлементыНастроек)
	Поиск = Новый Структура("СвойствоНастройки, ЭтоФлажок", "Значение", Истина);
	НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
	
	Для Каждого Элемент Из НайденныеЭлементы Цикл 
		ЭлементыНастроек.Удалить(Элемент);
	КонецЦикла;
КонецПроцедуры

Процедура НайтиЗначенияКакФлажки(Форма, ЭлементыНастроек, ИменаРеквизитов)
	Поиск = Новый Структура;
	Поиск.Вставить("ТипЗначения", Новый ОписаниеТипов("Булево"));
	НайденныеЭлементы = ЭлементыНастроек.Скопировать(Поиск);
	НайденныеЭлементы.Свернуть("ИндексНастройки, ТипЗначения", "КонтрольнаяСумма");
	
	НайденныеЭлементы = НайденныеЭлементы.НайтиСтроки(Новый Структура("КонтрольнаяСумма", 2));
	Если НайденныеЭлементы.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	Поиск = Новый Структура("СвойствоНастройки, ИндексНастройки");
	Для Каждого Элемент Из НайденныеЭлементы Цикл 
		Поиск.СвойствоНастройки = "Использование";
		Поиск.ИндексНастройки = Элемент.ИндексНастройки;
		
		ЭлементФлажка = ЭлементыНастроек.НайтиСтроки(Поиск);
		Если ЭлементФлажка.Количество() = 0 Тогда 
			Продолжить;
		КонецЕсли;
		
		ЭлементФлажка = ЭлементФлажка[0];
		
		Если ТипЗнч(ЭлементФлажка.ДоступныеЗначения) = Тип("СписокЗначений")
			И ЭлементФлажка.ДоступныеЗначения.Количество() > 0 Тогда 
			Продолжить;
		КонецЕсли;
		
		Если ТипЗнч(ЭлементФлажка.Поле) <> Тип("ДекорацияФормы") Тогда 
			Продолжить;
		КонецЕсли;
		
		Поиск.СвойствоНастройки = "Значение";
		
		ЭлементЗначения = ЭлементыНастроек.НайтиСтроки(Поиск);
		Если ЭлементЗначения.Количество() = 0 Тогда 
			Продолжить;
		КонецЕсли;
		
		ЭлементФлажка.СвойствоНастройки = "Значение";
		ЭлементФлажка.ЭтоФлажок = Истина;
		ЭлементФлажка.ЭтоЗначениеКакФлажок = Истина;
		
		ЭлементЗначения = ЭлементЗначения[0];
		ЭлементЗначения.СвойствоНастройки = "Использование";
		ЭлементЗначения.ЭтоФлажок = Истина;
		ЭлементЗначения.ЭтоЗначениеКакФлажок = Истина;
		ЭлементЗначения.Поле.Видимость = Ложь;
	КонецЦикла;
КонецПроцедуры

// Переопределяет при необходимости свойства элементов формы, связанных с настройками:
// видимость, Ширина, РастягиватьПоГоризонтали и др.
// 
// Параметры:
//  Форма - ФормаКлиентскогоПриложения
//        - РасширениеУправляемойФормыДляОтчета:
//    * Отчет - ОтчетОбъект
//  ЭлементыНастроек - см. ПалитраКоллекцииЭлементовНастроек
//  СвойстваЭлементов - Структура:
//    * Группы - Структура
//    * Поля - ТаблицаЗначений
//
Процедура УстановитьСвойстваЭлементовФормыНастроек(Форма, ЭлементыНастроек, СвойстваЭлементов)
		КомпоновщикНастроек = Форма.Отчет.КомпоновщикНастроек;
	
	#Область УстановкаСвойствЭлементовИспользование
	
	Исключения = Новый Массив;
	Исключения.Добавить(ВидСравненияКомпоновкиДанных.Равно);
	Исключения.Добавить(ВидСравненияКомпоновкиДанных.Содержит);
	Исключения.Добавить(ВидСравненияКомпоновкиДанных.Заполнено);
	Исключения.Добавить(ВидСравненияКомпоновкиДанных.Подобно);
	Исключения.Добавить(ВидСравненияКомпоновкиДанных.ВСписке);
	Исключения.Добавить(ВидСравненияКомпоновкиДанных.ВСпискеПоИерархии);
	
	НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Новый Структура("СвойствоНастройки", "Использование"));
	Для Каждого Элемент Из НайденныеЭлементы Цикл 
		Поле = Элемент.Поле; // ПолеФормы
		СвойстваПоля = СвойстваЭлементов.Поля.Найти(Элемент.ИндексНастройки, "ИндексНастройки");
		
		Если ЗначениеЗаполнено(СвойстваПоля.Представление) Тогда 
			Поле.Заголовок = СвойстваПоля.Представление;
		КонецЕсли;
		
		Если ТипЗнч(Поле) = Тип("ПолеФормы") Тогда 
			Поле.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Право;
			Поле.УстановитьДействие("ПриИзменении", "Подключаемый_ЭлементНастройки_ПриИзменении");
		ИначеЕсли ТипЗнч(Поле) = Тип("ДекорацияФормы") Тогда 
			Поле.Видимость = Истина;
		КонецЕсли;
		
		Если СтрДлина(Поле.Заголовок) > 40 Тогда
			Поле.ВысотаЗаголовка = 2;
		КонецЕсли;
		
		ЭлементНастройки = СвойстваПоля.ЭлементНастройки;
		Если ТипЗнч(ЭлементНастройки) = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
			Поле.Заголовок = Поле.Заголовок + ":";
		ИначеЕсли ТипЗнч(ЭлементНастройки) = Тип("ЭлементОтбораКомпоновкиДанных") Тогда 
			
			Условие = ЭлементНастройки.ВидСравнения;
			Если ЗначениеЗаполнено(ЭлементНастройки.ИдентификаторПользовательскойНастройки) Тогда 
				
				ЭлементПользовательскойНастройки = КомпоновщикНастроек.ПользовательскиеНастройки.Элементы.Найти(
					ЭлементНастройки.ИдентификаторПользовательскойНастройки);
				
				Если ЭлементПользовательскойНастройки <> Неопределено Тогда 
					Условие = ЭлементПользовательскойНастройки.ВидСравнения;
				КонецЕсли;
			КонецЕсли;
			
			Если Исключения.Найти(Условие) <> Неопределено Тогда 
				Поле.Заголовок = Поле.Заголовок + ":";
			ИначеЕсли Не ЗначениеЗаполнено(ЭлементНастройки.Представление) Тогда 
				Поле.Заголовок = Поле.Заголовок + " (" + НРег(Условие) + "):";
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	#КонецОбласти
	
	#Область УстановкаСвойствЭлементовЭлементыНастроек
	
	НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Новый Структура("СвойствоНастройки", "ВидСравнения"));
	Для Каждого Элемент Из НайденныеЭлементы Цикл
		Поле = Элемент.Поле; // ПолеФормы 
		Поле.Видимость = Ложь;
	КонецЦикла;
	
	#КонецОбласти
	
	#Область УстановкаСвойствЭлементовЗначение
	
	СвязанныеЭлементы = ЭлементыНастроек.Скопировать(Новый Структура("СвойствоНастройки", "Использование"));
	
	ПараметрыПодбора = Новый Соответствие;
	РасширенноеОписаниеТипов = Новый Соответствие;
	
	НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Новый Структура("СвойствоНастройки", "Значение"));
	Для Каждого Элемент Из НайденныеЭлементы Цикл 
		Поле = Элемент.Поле; // ПолеФормы
		
		СвязанныйЭлемент = СвязанныеЭлементы.Найти(Элемент.ИндексНастройки, "ИндексНастройки");
		СвязанноеПоле = СвязанныйЭлемент.Поле; // ПолеФормы
		
		Если ТипЗнч(Поле) = Тип("ДекорацияФормы") Тогда 
			Если СтрЗаканчиваетсяНа(СвязанноеПоле.Заголовок, ":") Тогда 
				СвязанноеПоле.Заголовок = Лев(СвязанноеПоле.Заголовок, СтрДлина(СвязанноеПоле.Заголовок) - 1);
			КонецЕсли;
			
			СвязанноеПоле.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
			Поле.Заголовок = СвязанноеПоле.Заголовок;
		Иначе // Поле ввода.
			СвойстваПоля = СвойстваЭлементов.Поля.Найти(Элемент.ИндексНастройки, "ИндексНастройки");
			ЗаполнитьЗначенияСвойств(Поле, СвойстваПоля,, "ПоложениеЗаголовка");
			
			Если ЭтоОсновнаяФорма(Форма) И Не ВыводитьЗаголовкиНастроек(Форма) Тогда 
				Если СтрЗаканчиваетсяНа(СвязанноеПоле.Заголовок, ":") Тогда 
					Заголовок = Лев(СвязанноеПоле.Заголовок, СтрДлина(СвязанноеПоле.Заголовок) - 1);
				Иначе
					Заголовок = СвязанноеПоле.Заголовок;
				КонецЕсли;
				
				Поле.ПодсказкаВвода = Заголовок;
				Поле.Подсказка = Поле.ПодсказкаВвода;
			Иначе
				Поле.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Авто;
			КонецЕсли;
			
			Если ТипЗнч(СвязанноеПоле) = Тип("ДекорацияФормы") Тогда 
				СвязанноеПоле.Заголовок = " ";
			Иначе
				СвязанноеПоле.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
				СвязанноеПоле.ГоризонтальноеПоложениеВГруппе = ГоризонтальноеПоложениеЭлемента.Право;
			КонецЕсли;
			
			Если Элемент.ЭтоФлажок Тогда 
				Поле.Видимость = Ложь;
				Продолжить;
			КонецЕсли;
			
			Поле.УстановитьДействие("ПриИзменении", "Подключаемый_ЭлементНастройки_ПриИзменении");
			Если Элемент.ЭтоСписок Тогда
				Поле.УстановитьДействие("НачалоВыбора", "Подключаемый_ЭлементНастройки_НачалоВыбора");
			КонецЕсли;
			
			Поле.ФормаВыбора = Элемент.ФормаВыбора;
			Если ЗначениеЗаполнено(Поле.ФормаВыбора) Тогда 
				ПараметрыПодбора.Вставить(Элемент.ИндексНастройки, Поле.ФормаВыбора);
			КонецЕсли;
			
			Результат = ОбщегоНазначенияКлиентСервер.ДополнитьСписок(Поле.СписокВыбора, Элемент.ДоступныеЗначения, Ложь, Истина);
			Поле.РежимВыбораИзСписка = Не Элемент.ЭтоСписок И Результат.Всего > 0;
			
			Если Поле.РастягиватьПоГоризонтали = Неопределено Тогда
				Поле.РастягиватьПоГоризонтали = Истина;
				Поле.АвтоМаксимальнаяШирина = Ложь;
				Поле.МаксимальнаяШирина = 40;
			КонецЕсли;
			
			Если Элемент.ТипЗначения = Неопределено Тогда 
				Продолжить;
			КонецЕсли;
			
			РасширенноеОписаниеТипа = РасширенноеОписаниеТипов(Элемент.ТипЗначения, Истина, ПараметрыПодбора);
			РасширенноеОписаниеТипов.Вставить(Элемент.ИндексНастройки, РасширенноеОписаниеТипа);
			
			Поле.ДоступныеТипы = РасширенноеОписаниеТипа.ОписаниеТиповДляФормы;
			Поле.ОграничениеТипа = РасширенноеОписаниеТипа.ОписаниеТиповДляФормы;
			
			Если СтрДлина(Поле.Заголовок) > 40 Тогда
				Поле.ВысотаЗаголовка = 2;
			КонецЕсли;
			
			Если РасширенноеОписаниеТипа.КоличествоТипов = 1 Тогда 
				Если РасширенноеОписаниеТипа.СодержитТипЧисло Тогда 
					Поле.КнопкаВыбора = Поле.СписокВыбора.Количество() = 0 Или Элемент.ЭтоСписок;
					Если Поле.РастягиватьПоГоризонтали = Истина Тогда
						Поле.РастягиватьПоГоризонтали = Ложь;
					КонецЕсли;
				ИначеЕсли РасширенноеОписаниеТипа.СодержитТипДата Тогда 
					Поле.МаксимальнаяШирина = 25;
				ИначеЕсли РасширенноеОписаниеТипа.СодержитТипБулево Тогда 
					Если Поле.СписокВыбора.Количество() = 0 Тогда 
						Поле.МаксимальнаяШирина = 5;
					Иначе
						Поле.РастягиватьПоГоризонтали = Ложь;
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	ДополнительныеСвойства = КомпоновщикНастроек.Настройки.ДополнительныеСвойства;
	ДополнительныеСвойства.Вставить("ПараметрыПодбора", ПараметрыПодбора);
	ДополнительныеСвойства.Вставить("РасширенноеОписаниеТипов", РасширенноеОписаниеТипов);
	
	#КонецОбласти
КонецПроцедуры

Функция ВыводитьЗаголовкиНастроек(Форма)
	
	РеквизитыФормы = Форма.ПолучитьРеквизиты();
	ИмяИскомогоРеквизита = "ВыводитьЗаголовкиНастроек";
	
	Для Каждого Реквизит Из РеквизитыФормы Цикл 
		
		Если Реквизит.Имя = ИмяИскомогоРеквизита Тогда 
			Возврат Форма[ИмяИскомогоРеквизита];
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

// Выделяет группу для списка, ссылающегося на настройку с видом сравнения:
// ВСписке, НеВСписке и т.д.
// 
// Параметры:
//   ЭлементыНастроек - см. ПалитраКоллекцииЭлементовНастроек
//   СвойстваЭлементов - Структура:
//   * Группы - Структура
//   * Поля - ТаблицаЗначений
//
Процедура ВынестиСписокВОтдельнуюГруппу(ЭлементыНастроек, СвойстваЭлементов)
	Поиск = Новый Структура("ЭтоСписок", Истина);
	Статистика = ЭлементыНастроек.Скопировать(Поиск);
	Статистика.Свернуть("ИндексНастройки");
	
	Если Статистика.Количество() <> 1 Тогда 
		Возврат;
	КонецЕсли;
	
	ИндексНастройки = ЭлементыНастроек.НайтиСтроки(Поиск)[0].ИндексНастройки;
	СвойстваПоля = СвойстваЭлементов.Поля.Найти(ИндексНастройки, "ИндексНастройки");
	Если ЗначениеЗаполнено(СвойстваПоля.ИдентификаторГруппы) Тогда 
		Возврат;
	КонецЕсли;
	
	ИдентификаторГруппы = "_" + СтрЗаменить(Новый УникальныйИдентификатор, "-", "");
	СвойстваПоля.ИдентификаторГруппы = ИдентификаторГруппы;
	СвойстваЭлементов.Группы.Вставить(ИдентификаторГруппы, СвойстваГруппыЭлементовФормы());
КонецПроцедуры

Функция ЭлементыНастроекГруппы(ЭлементыНастроек, СвойстваПолейГруппы)
	ЭлементыНастроекГруппы = ЭлементыНастроек.СкопироватьКолонки();
	
	Поиск = Новый Структура("ИндексНастройки");
	Для Каждого Свойства Из СвойстваПолейГруппы Цикл 
		Поиск.ИндексНастройки = Свойства.ИндексНастройки;
		НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
		Для Каждого Элемент Из НайденныеЭлементы Цикл 
			ЗаполнитьЗначенияСвойств(ЭлементыНастроекГруппы.Добавить(), Элемент);
		КонецЦикла;
	КонецЦикла;
	
	Возврат ЭлементыНастроекГруппы;
КонецФункции

// Распределение элементов формы настроек в иерархии

Процедура ПодготовитьЭлементыФормыНастроекКРаспределению(ЭлементыНастроек, Группировка, ЭтоОсновнаяФорма, ДополнительныеСвойства)
	#Область ПередПодготовкой
	
	Статистика = ЭлементыНастроек.Скопировать();
	Статистика.Свернуть("ИндексНастройки");
	
 	КоличествоКолонок = 1;
	Если Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяЕслиВозможно Тогда 
		КоличествоКолонок = Мин(?(ЭтоОсновнаяФорма, 3, 2), Статистика.Количество());
	ИначеЕсли Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда Тогда 
		КоличествоКолонок = Статистика.Количество();
	КонецЕсли;
	КоличествоКолонок = Макс(1, КоличествоКолонок);
	
	УпорядочитьЭлементыФормыНастроек(ЭлементыНастроек, ДополнительныеСвойства);
	
	#КонецОбласти
	
	#Область УстановкаНомеровКолонок
	
	Статистика = ЭлементыНастроек.Скопировать();
	Статистика.Свернуть("Порядок, ИндексНастройки");
	
	КоличествоЭлементов = Статистика.Количество();
	Индекс = 0;
	ГраницаСвойств = КоличествоЭлементов - 1;
	
	Шаг = КоличествоЭлементов / КоличествоКолонок;
	ГраницаРазрыва = ?(КоличествоЭлементов % КоличествоКолонок = 0, Шаг - 1, Цел(Шаг));
	Шаг = ?(ГраницаРазрыва = 0, 1, Окр(Шаг));
	
	Поиск = Новый Структура("ИндексНастройки");
	Для НомерКолонки = 1 По КоличествоКолонок Цикл 
		Пока Индекс <= ГраницаРазрыва Цикл 
			Поиск.ИндексНастройки = Статистика[Индекс].ИндексНастройки;
			НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
			Для Каждого Элемент Из НайденныеЭлементы Цикл 
				Элемент.НомерКолонки = НомерКолонки;
			КонецЦикла;
			Индекс = Индекс + 1;
		КонецЦикла;
		
		ГраницаРазрыва = ГраницаРазрыва + Шаг;
		Если ГраницаРазрыва > ГраницаСвойств Тогда 
			ГраницаРазрыва = ГраницаСвойств;
		КонецЕсли;
	КонецЦикла;
	
	РаспределитьСпискиПоКолонкамПропорционально(ЭлементыНастроек, КоличествоКолонок);
	
	#КонецОбласти
	
	#Область УстановкаНомеровГрупп
	
	ВариантыПоиска = Новый Массив;
	ВариантыПоиска.Добавить(Новый Структура("НомерГруппы, ЭтоФлажок, ЭтоСписок", 0, Ложь, Ложь));
	ВариантыПоиска.Добавить(Новый Структура("НомерГруппы, ЭтоФлажок, ЭтоСписок", 0, Истина, Ложь));
	ВариантыПоиска.Добавить(Новый Структура("НомерГруппы, ЭтоФлажок, ЭтоСписок", 0, Ложь, Истина));
	
	НомерГруппы = 1;
	Для Каждого Поиск Из ВариантыПоиска Цикл 
		НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
		
		ПредыдущийИндекс = Неопределено;
		Для Каждого Элемент Из НайденныеЭлементы Цикл 
			Если Элемент.ЭтоФлажок Или Элемент.ЭтоСписок Тогда 
				Индекс = Элемент.ИндексНастройки;
			Иначе
				Индекс = ЭлементыНастроек.Индекс(Элемент);
			КонецЕсли;
			
			Если ПредыдущийИндекс = Неопределено Тогда 
				ПредыдущийИндекс = Индекс;
			КонецЕсли;
			
			Если ((Элемент.ЭтоФлажок Или Элемент.ЭтоСписок) И Индекс <> ПредыдущийИндекс)
				Или (Не Элемент.ЭтоФлажок И Не Элемент.ЭтоСписок И Индекс > ПредыдущийИндекс + 1) Тогда 
				НомерГруппы = НомерГруппы + 1;
			КонецЕсли;
			
			Элемент.НомерГруппы = НомерГруппы;
			ПредыдущийИндекс = Индекс;
		КонецЦикла;
		
		НомерГруппы = НомерГруппы + 1;
	КонецЦикла;
	
	#КонецОбласти
КонецПроцедуры

Процедура УпорядочитьЭлементыФормыНастроек(ЭлементыНастроек, ДополнительныеСвойства)
	
	ПорядокЭлементовНастроек = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
		ДополнительныеСвойства, "ПорядокЭлементовНастроек", Новый Соответствие);
	
	Поиск = Новый Структура("ИдентификаторНастройки");
	
	Если ПорядокЭлементовНастроек.Количество() = 0 Тогда 
		
		НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Новый Структура("ЭтоПериод", Истина));
		
		Для Каждого Элемент Из НайденныеЭлементы Цикл 
			Элемент.Порядок = -1;
		КонецЦикла;
		
		Порядок = 0;
		
	Иначе
		
		Для Каждого ПорядокЭлемента Из ПорядокЭлементовНастроек Цикл 
			
			Поиск.ИдентификаторНастройки = ПорядокЭлемента.Ключ;
			НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
			
			Для Каждого Элемент Из НайденныеЭлементы Цикл 
				Элемент.Порядок = ПорядокЭлемента.Значение;
			КонецЦикла;
			
		КонецЦикла;
		
		ИндексЭлементовНастроек = ЭлементыНастроек.Скопировать();
		ИндексЭлементовНастроек.Свернуть("Порядок, ИдентификаторНастройки");
		ИндексЭлементовНастроек.Сортировать("Порядок");
		
		Граница = ИндексЭлементовНастроек.Количество() - 1;
		Порядок = ?(Граница >= 0, ИндексЭлементовНастроек[Граница].Порядок, 0);
		
	КонецЕсли;
	
	Для Каждого Элемент Из ЭлементыНастроек Цикл 
		
		Если Элемент.Порядок <> 0 Тогда 
			Продолжить;
		КонецЕсли;
		
		Порядок = Порядок + 1;
		
		Поиск.ИдентификаторНастройки = Элемент.ИдентификаторНастройки;
		СвязанныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
		
		Для Каждого СвязанныйЭлемент Из СвязанныеЭлементы Цикл 
			СвязанныйЭлемент.Порядок = Порядок;
		КонецЦикла;
		
	КонецЦикла;
	
	ЭлементыНастроек.Сортировать("Порядок, ИндексНастройки");
	
	АктуальныйПорядокЭлементовНастроек = ЭлементыНастроек.Скопировать();
	АктуальныйПорядокЭлементовНастроек.Свернуть("Порядок, ИдентификаторНастройки");
	
	Для Каждого ПорядокЭлемента Из АктуальныйПорядокЭлементовНастроек Цикл 
		ПорядокЭлементовНастроек.Вставить(ПорядокЭлемента.ИдентификаторНастройки, ПорядокЭлемента.Порядок);
	КонецЦикла;
	
	ДополнительныеСвойства.Вставить("ПорядокЭлементовНастроек", ПорядокЭлементовНастроек);
	
КонецПроцедуры

Процедура РаспределитьСпискиПоКолонкамПропорционально(ЭлементыНастроек, КоличествоКолонок)
	Если КоличествоКолонок <> 2
		Или ЭлементыНастроек.Найти(Истина, "ЭтоСписок") = Неопределено Тогда 
		Возврат;
	КонецЕсли;
	
	ОписаниеЧисла = Новый ОписаниеТипов("Число");
	
	Статистика = ЭлементыНастроек.Скопировать();
	Статистика.Свернуть("ИндексНастройки, ЭтоСписок, НомерКолонки");
	Статистика.Колонки.Добавить("Списков", ОписаниеЧисла);
	
	Для Каждого Элемент Из Статистика Цикл 
		Элемент.Списков = Число(Элемент.ЭтоСписок);
	КонецЦикла;
	
	Статистика.Свернуть("НомерКолонки", "Списков");
	
	Списков = Статистика.Итог("Списков");
	Если Списков = 1 Тогда 
		Возврат;
	КонецЕсли;
	
	Статистика.Сортировать("Списков");
	
	Среднее = Окр(Списков / Статистика.Количество(), 0, РежимОкругления.Окр15как10);
	Приемник = Статистика[0];
	Источник = Статистика[Статистика.Количество() - 1];
	
	Отклонение = Среднее - Приемник.Списков;
	Если Отклонение = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	Поиск = Новый Структура("ЭтоСписок, НомерКолонки", Истина, Источник.НомерКолонки);
	ЭлементыИсточника = ЭлементыНастроек.Скопировать(Поиск);
	ЭлементыИсточника.Свернуть("ИндексНастройки");
	Если Приемник.НомерКолонки > Источник.НомерКолонки Тогда 
		ЭлементыИсточника.Сортировать("ИндексНастройки Убыв");
	КонецЕсли;
	
	Отклонение = Мин(Отклонение, ЭлементыИсточника.Количество());
	Поиск = Новый Структура("ИндексНастройки");
	
	Индекс = 0;
	Пока Отклонение > 0 Цикл 
		Поиск.ИндексНастройки = ЭлементыИсточника[Индекс].ИндексНастройки;
		СвязанныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
		Для Каждого Элемент Из СвязанныеЭлементы Цикл 
			Элемент.НомерКолонки = Приемник.НомерКолонки;
		КонецЦикла;
		
		Индекс = Индекс + 1;
		Отклонение = Отклонение - 1;
	КонецЦикла;
КонецПроцедуры

Процедура РаспределитьЭлементыФормыНастроек(Форма, Знач Группа, ЭлементыНастроек)
	КоличествоКолонок = 0;
	Если ЭлементыНастроек.Количество() > 0 Тогда 
		КоличествоКолонок = ЭлементыНастроек[ЭлементыНастроек.Количество() - 1].НомерКолонки;
	КонецЕсли;
	
	Элементы = Форма.Элементы;
	
	Для НомерКолонки = 1 По КоличествоКолонок Цикл 
		ПризнакиЭлементов = ЭлементыНастроек.Скопировать(Новый Структура("НомерКолонки", НомерКолонки));
		ПризнакиЭлементов.Свернуть("ЭтоФлажок, ЭтоСписок, НомерГруппы");
		
		ТолькоПоляВвода = ПризнакиЭлементов.Найти(Истина, "ЭтоФлажок") = Неопределено
			И ПризнакиЭлементов.Найти(Истина, "ЭтоСписок") = Неопределено;
		
		ИмяКолонки = Группа.Имя + "Колонка" + НомерКолонки;
		Колонка = ?(КоличествоКолонок = 1, Группа, Элементы.Найти(ИмяКолонки));
		Если Колонка = Неопределено Тогда 
			Колонка = ГруппаЭлементовФормыНастроек(Форма, Группа, ИмяКолонки);
			Колонка.Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Колонка %1'"), НомерКолонки);
			
			Если ТолькоПоляВвода Тогда 
				Колонка.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
			КонецЕсли;
		КонецЕсли;
		
		Если НомерКолонки > 1 Тогда 
			Колонка.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение;
		КонецЕсли;
		
		Если ТолькоПоляВвода Тогда 
			РаспределитьЭлементыФормыНастроекПоСвойствам(Форма, Колонка, ЭлементыНастроек, НомерКолонки);
			Продолжить;
		КонецЕсли;
		
		НомерСтроки = 0;
		Для Каждого Признаки Из ПризнакиЭлементов Цикл 
			НомерСтроки = НомерСтроки + 1;
			Родитель = ИерархияЭлементовФормыНастроек(Форма, Колонка, Признаки, НомерСтроки, НомерКолонки);
			
			РаспределитьЭлементыФормыНастроекПоСвойствам(Форма, Родитель, ЭлементыНастроек, НомерКолонки, Признаки.НомерГруппы);
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

Процедура РаспределитьЭлементыФормыНастроекПоСвойствам(Форма, Родитель, ЭлементыНастроек, НомерКолонки, НомерГруппы = Неопределено)
	Элементы = Форма.Элементы;
	
	СвойстваНастроек = СтрРазделить("Использование, ВидСравнения, Значение", ", ", Ложь);
	Для Каждого СвойствоНастройки Из СвойстваНастроек Цикл 
		ИмяГруппы = Родитель.Имя + СвойствоНастройки;
		Группа = ГруппаЭлементовФормыНастроек(Форма, Родитель, ИмяГруппы);
		Группа.Заголовок = СвойствоНастройки;
		Группа.Видимость = (СвойствоНастройки <> "ВидСравнения");
		
		Поиск = Новый Структура("СвойствоНастройки, НомерКолонки", СвойствоНастройки, НомерКолонки);
		Если НомерГруппы <> Неопределено Тогда 
			Поиск.Вставить("НомерГруппы", НомерГруппы);
		КонецЕсли;
		
		НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
		Для Каждого Элемент Из НайденныеЭлементы Цикл 
			Группа.Объединенная = СвойствоНастройки = "Использование" И Элемент.ЭтоСписок;
			Элементы.Переместить(Элемент.Поле, Группа);
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

Функция ИерархияЭлементовФормыНастроек(Форма, Родитель, Признаки, НомерСтроки, НомерКолонки)
	ИмяСтроки = Родитель.Имя + "Строка" + НомерСтроки;
	Строка = ГруппаЭлементовФормыНастроек(Форма, Родитель, ИмяСтроки);
	Строка.Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Строка %1.%2'"), НомерКолонки, НомерСтроки);
	
	Если Не Признаки.ЭтоСписок Тогда 
		Строка.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	КонецЕсли;
	
	Если Признаки.ЭтоФлажок Или Признаки.ЭтоСписок Тогда 
		Возврат Строка;
	КонецЕсли;
	
	ИмяКолонки = Строка.Имя + "Колонка1";
	Колонка = ГруппаЭлементовФормыНастроек(Форма, Строка, ИмяКолонки);
	Колонка.Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Колонка %1.%2.1'"), НомерКолонки, НомерСтроки);
	
	Колонка.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	
	Возврат Колонка;
КонецФункции

Функция ГруппаЭлементовФормыНастроек(Форма, Родитель, ИмяГруппы)
	Элементы = Форма.Элементы;
	
	Группа = Элементы.Найти(ИмяГруппы);
	Если Группа <> Неопределено Тогда 
		Возврат Группа;
	КонецЕсли;
	
	Группа = Элементы.Добавить(ИмяГруппы, Тип("ГруппаФормы"), Родитель);
	Группа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
	Группа.ОтображатьЗаголовок = Ложь;
	Группа.Отображение = ОтображениеОбычнойГруппы.Нет;
	Группа.Поведение = ПоведениеОбычнойГруппы.Обычное;
	Группа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
	
	Если ЭтоОсновнаяФорма(Форма) И Не ВыводитьЗаголовкиНастроек(Форма) Тогда 
		Группа.Объединенная = Ложь;
	КонецЕсли;
	
	Возврат Группа;
КонецФункции

Функция ЭтоОсновнаяФорма(Форма)
	
	Возврат (Форма.ТипФормыОтчета = ТипФормыОтчета.Основная);
	
КонецФункции

// Вывод стилизованных элементов формы настроек.

Процедура ВывестиСтилизованныеЭлементыФормыНастроек(Форма, ЭлементыНастроек, ОписаниеНастроек, ИменаРеквизитов, ВидыЭлементов)
	// Изменение реквизитов.
	ПутьКДаннымЭлементов = Новый Структура("ПоИмени, ПоИндексу", Новый Соответствие, Новый Соответствие);
	
	РеквизитыДобавляемые = РеквизитыЭлементовНастроекДобавляемые(ЭлементыНастроек, ВидыЭлементов, ИменаРеквизитов, ПутьКДаннымЭлементов);
	РеквизитыУдаляемые = РеквизитыЭлементовНастроекУдаляемые(ВидыЭлементов, ИменаРеквизитов, ПутьКДаннымЭлементов);
	
	Форма.ИзменитьРеквизиты(РеквизитыДобавляемые, РеквизитыУдаляемые);
	УдалитьКомандыЭлементовНастроек(Форма, РеквизитыУдаляемые);
	
	Форма.ПутьКДаннымЭлементов = ПутьКДаннымЭлементов;
	
	// Изменение элементов.
	ВывестиПериодыНастроек(Форма, ЭлементыНастроек, ИменаРеквизитов);
	ВывестиСпискиНастроек(Форма, ЭлементыНастроек, ОписаниеНастроек, ИменаРеквизитов);
	ВывестиЗначенияКакПоляФлажков(Форма, ЭлементыНастроек, ИменаРеквизитов);
КонецПроцедуры

Функция РеквизитыЭлементовНастроекДобавляемые(ЭлементыНастроек, ВидыЭлементов, ИменаРеквизитов, ПутьКДаннымЭлементов)
	РеквизитыДобавляемые = Новый Массив;
	
	ТипыЭлементов = Новый Структура;
	ТипыЭлементов.Вставить("Период", Новый ОписаниеТипов("СтандартныйПериод"));
	ТипыЭлементов.Вставить("Список", Новый ОписаниеТипов("СписокЗначений"));
	ТипыЭлементов.Вставить("Флажок", Новый ОписаниеТипов("Булево"));
	
	ПризнакиВидовЭлементов = Новый Структура("Период, Список, Флажок", "ЭтоПериод", "ЭтоСписок", "ЭтоЗначениеКакФлажок");
	СвойстваВидовЭлементов = Новый Структура("Период, Список, Флажок", "Значение", "Значение", "Использование");
	
	Для Каждого ВидЭлемента Из ВидыЭлементов Цикл 
		Признак = ПризнакиВидовЭлементов[ВидЭлемента];
		
		Сгенерированные = ИменаРеквизитов.Сгенерированных[ВидЭлемента];
		Предопределенные = ИменаРеквизитов.Предопределенных[ВидЭлемента];
		
		ИндексПредопределенных = -1;
		ГраницаПредопределенных = Предопределенные.ВГраница();
		
		Поиск = Новый Структура;
		Поиск.Вставить(Признак, Истина);
		Поиск.Вставить("СвойствоНастройки", "Значение");
		
		НайденныеЭлементы = ЭлементыНастроек.Скопировать(Поиск);
		Для Каждого Элемент Из НайденныеЭлементы Цикл 
			Если ГраницаПредопределенных >= НайденныеЭлементы.Индекс(Элемент) Тогда 
				ИндексПредопределенных = ИндексПредопределенных + 1;
				ПутьКДаннымЭлементов.ПоИмени.Вставить(Предопределенные[ИндексПредопределенных], Элемент.ИндексНастройки);
				ПутьКДаннымЭлементов.ПоИндексу.Вставить(Элемент.ИндексНастройки, Предопределенные[ИндексПредопределенных]);
				Продолжить;
			КонецЕсли;
			
			Поле = Элемент.Поле; // ПолеФормы
			ЗаголовокЭлемента = Поле.Заголовок;
			Если СтрЗаканчиваетсяНа(Поле.Имя, СвойстваВидовЭлементов[ВидЭлемента]) Тогда
				Позиция = СтрНайти(Поле.Имя, СвойстваВидовЭлементов[ВидЭлемента], НаправлениеПоиска.СКонца);
				ШаблонИмениЭлемента = Лев(Поле.Имя, Позиция - 1) + "%1";
			Иначе
				ШаблонИмениЭлемента = Поле.Имя;
			КонецЕсли;
			
			ИмяРеквизита = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонИмениЭлемента, ВидЭлемента);
			Если Сгенерированные.Найти(ИмяРеквизита) = Неопределено Тогда 
				ТипЭлемента = Элемент.ТипЗначения;
				ТипыЭлементов.Свойство(ВидЭлемента, ТипЭлемента);
				
				РеквизитыДобавляемые.Добавить(Новый РеквизитФормы(ИмяРеквизита, ТипЭлемента,, ЗаголовокЭлемента));
			КонецЕсли;
			
			ПутьКДаннымЭлементов.ПоИмени.Вставить(ИмяРеквизита, Элемент.ИндексНастройки);
			ПутьКДаннымЭлементов.ПоИндексу.Вставить(Элемент.ИндексНастройки, ИмяРеквизита);
		КонецЦикла;
	КонецЦикла;
	
	Возврат РеквизитыДобавляемые;
КонецФункции

Функция РеквизитыЭлементовНастроекУдаляемые(ВидыЭлементов, ИменаРеквизитов, ПутьКДаннымЭлементов)
	РеквизитыУдаляемые = Новый Массив;
	
	Для Каждого ВидЭлемента Из ВидыЭлементов Цикл 
		Сгенерированные = ИменаРеквизитов.Сгенерированных[ВидЭлемента];
		Для Каждого ИмяРеквизита Из Сгенерированные Цикл 
			Если ПутьКДаннымЭлементов.ПоИмени[ИмяРеквизита] = Неопределено Тогда 
				РеквизитыУдаляемые.Добавить(ИмяРеквизита);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Возврат РеквизитыУдаляемые;
КонецФункции

Процедура УдалитьКомандыЭлементовНастроек(Форма, РеквизитыУдаляемые)
	СуффиксыКоманд = СтрРазделить("ВыбратьПериод, Подбор, ВставитьИзБуфера", ", ", ЛОЖЬ);
	
	Для Каждого ИмяРеквизита Из РеквизитыУдаляемые Цикл 
		Для Каждого Суффикс Из СуффиксыКоманд Цикл 
			Команда = Форма.Команды.Найти(ИмяРеквизита + Суффикс);
			Если Команда <> Неопределено Тогда 
				Форма.Команды.Удалить(Команда);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
КонецПроцедуры

// Вывод периодов элементов формы настроек

Процедура ВывестиПериодыНастроек(Форма, ЭлементыНастроек, ИменаРеквизитов)
	НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Новый Структура("ЭтоПериод, СвойствоНастройки", Истина, "Значение"));
	Если НайденныеЭлементы.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	Элементы = Форма.Элементы;
	ИменаРеквизитовПредопределенных = ИменаРеквизитов.Предопределенных.Период;
	
	ВариантПредставления = Форма.НастройкиОтчета.ВариантПредставленияПериода;
	ЭтоСтандартноеПредставление = (ВариантПредставления = Перечисления.ВариантыПредставленияПериода.Стандартный);
	
	Для Каждого Элемент Из НайденныеЭлементы Цикл 
		СвязанныеЭлементы = ЭлементыНастроек.НайтиСтроки(Новый Структура("ИндексНастройки", Элемент.ИндексНастройки));
		Для Каждого СвязанныйЭлемент Из СвязанныеЭлементы Цикл 
			СвязанныйЭлемент.Поле.Видимость = (СвязанныйЭлемент.СвойствоНастройки = "Использование");
		КонецЦикла;
		
		Период = ИнициализироватьПериод(Форма, Элемент.ИндексНастройки);
		
		Поле = Элемент.Поле;
		Родитель = Поле.Родитель; // ГруппаФормы
		
		СледующийЭлемент = Неопределено;
		ИндексЭлемента = Родитель.ПодчиненныеЭлементы.Индекс(Поле);
		Если Родитель.ПодчиненныеЭлементы.Количество() > ИндексЭлемента + 1 Тогда 
			СледующийЭлемент = Родитель.ПодчиненныеЭлементы.Получить(ИндексЭлемента + 1);
		КонецЕсли;
		
		ИмяРеквизита = Форма.ПутьКДаннымЭлементов.ПоИндексу[Элемент.ИндексНастройки];
		Если ИменаРеквизитовПредопределенных.Найти(ИмяРеквизита) <> Неопределено Тогда 
			НайденныйЭлемент = Элементы.Найти(ИмяРеквизита);
			Элементы.Переместить(НайденныйЭлемент, Родитель, СледующийЭлемент);
			НайденныйЭлемент.Видимость = Истина;
			
			Для Каждого ЭлементПериода Из НайденныйЭлемент.ПодчиненныеЭлементы Цикл 
				ТипЭлементаПериода = ТипЗнч(ЭлементПериода);
				
				Если ТипЭлементаПериода = Тип("ПолеФормы") Тогда 
					ЭлементПериода.Заголовок = ЗаголовокЭлементаПериода(ЭлементПериода.Имя, Поле.Заголовок);
					ЭлементПериода.Подсказка = ЭлементПериода.Заголовок;
					ЭлементПериода.ПодсказкаВвода = ЭлементПериода.Заголовок;
				КонецЕсли;
				
				Если ЭтоСтандартноеПредставление Тогда 
					ЭлементПериода.Видимость = ТипЭлементаПериода <> Тип("КнопкаФормы")
						Или (ТипЭлементаПериода = Тип("КнопкаФормы")
						И СтрНачинаетсяС(ЭлементПериода.ИмяКоманды, "ВыбратьПериод"));
				Иначе
					ЭлементПериода.Видимость = (ТипЭлементаПериода = Тип("КнопкаФормы")
						Или ТипЭлементаПериода = Тип("ГруппаФормы"));
				КонецЕсли;
				
				УстановитьСвойстваКнопкиВыбораПериода(ЭлементПериода, Период, ЭтоСтандартноеПредставление);
				
			КонецЦикла;
			
			Продолжить;
		КонецЕсли;
		
		ШаблонИмениЭлемента = СтрЗаменить(Поле.Имя, "Значение", "%1%2");
		
		Группа = ГруппаЭлементовПериода(Элементы, Родитель, СледующийЭлемент, ШаблонИмениЭлемента, Поле.Заголовок);
		
		ДобавитьКомандуСдвигаПериода(Форма, Группа, ШаблонИмениЭлемента, ЭтоСтандартноеПредставление, -1);
		ДобавитьПолеПериода(Элементы, Группа, ШаблонИмениЭлемента, "ДатаНачала", Поле.Заголовок, ЭтоСтандартноеПредставление);
		
		ИмяЭлемента = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонИмениЭлемента, "Разделитель");
		Разделитель = Элементы.Найти(ИмяЭлемента);
		Если Разделитель = Неопределено Тогда 
			Разделитель = Элементы.Добавить(ИмяЭлемента, Тип("ДекорацияФормы"), Группа);
		КонецЕсли;
		Разделитель.Вид = ВидДекорацииФормы.Надпись;
		Разделитель.Заголовок = Символ(8211); // Среднее тире (en dash).
		Разделитель.Видимость = ЭтоСтандартноеПредставление;
		
		ДобавитьПолеПериода(Элементы, Группа, ШаблонИмениЭлемента, "ДатаОкончания", Поле.Заголовок, ЭтоСтандартноеПредставление);
		ДобавитьКомандуВыбораПериода(Форма, Группа, ШаблонИмениЭлемента, Период, ЭтоСтандартноеПредставление);
		ДобавитьКомандуСдвигаПериода(Форма, Группа, ШаблонИмениЭлемента, ЭтоСтандартноеПредставление);
	КонецЦикла;
КонецПроцедуры

Функция ГруппаЭлементовПериода(Элементы, Родитель, СледующийЭлемент, ШаблонИмени, Заголовок)
	ИмяЭлемента = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонИмени, "", "Период");
	
	Группа = Элементы.Найти(ИмяЭлемента);
	Если Группа = Неопределено Тогда 
		Группа = Элементы.Добавить(ИмяЭлемента, Тип("ГруппаФормы"), Родитель);
	КонецЕсли;
	Группа.Вид = ВидГруппыФормы.ОбычнаяГруппа;
	Группа.Отображение = ОтображениеОбычнойГруппы.Нет;
	Группа.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	Группа.Заголовок = Заголовок;
	Группа.ОтображатьЗаголовок = Ложь;
	Группа.РазрешитьИзменениеСостава = Ложь;
	
	Если СледующийЭлемент <> Неопределено Тогда 
		Элементы.Переместить(Группа, Родитель, СледующийЭлемент);
	КонецЕсли;
	
	Возврат Группа;
КонецФункции

Процедура ДобавитьПолеПериода(Элементы, Группа, ШаблонИмени, Свойство, ЗаголовокЭлементаНастройки, ЭтоСтандартноеПредставление)
	ИмяЭлемента = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонИмени, "", Свойство);
	
	Элемент = Элементы.Найти(ИмяЭлемента);
	Если Элемент = Неопределено Тогда 
		Элемент = Элементы.Добавить(ИмяЭлемента, Тип("ПолеФормы"), Группа);
	КонецЕсли;
	Элемент.Вид = ВидПоляФормы.ПолеВвода;
	Элемент.ПутьКДанным = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонИмени, "Период.", Свойство);
	Элемент.Ширина = 9;
	Элемент.РастягиватьПоГоризонтали = Ложь;
	Элемент.КнопкаВыбора = Истина;
	Элемент.КнопкаОткрытия = Ложь;
	Элемент.КнопкаОчистки = Ложь;
	Элемент.КнопкаРегулирования = Ложь;
	Элемент.РедактированиеТекста = Истина;
	Элемент.Заголовок = ЗаголовокЭлементаПериода(Свойство, ЗаголовокЭлементаНастройки);
	Элемент.Подсказка = Элемент.Заголовок;
	Элемент.ПодсказкаВвода = Элемент.Заголовок;
	Элемент.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
	Элемент.УстановитьДействие("ПриИзменении", "Подключаемый_Период_ПриИзменении");
	Элемент.Видимость = ЭтоСтандартноеПредставление;
КонецПроцедуры

Функция ЗаголовокЭлементаПериода(Свойство, ЗаголовокЭлементаНастройки)
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = '%1 (дата %2)'"),
		ЗаголовокЭлементаНастройки,
		?(СтрЗаканчиваетсяНа(НРег(Свойство), НРег("ДатаНачала")), НСтр("ru = 'начала'"), НСтр("ru = 'окончания'")));
	
КонецФункции

Процедура ДобавитьКомандуСдвигаПериода(Форма, Группа, ШаблонИмени, ЭтоСтандартноеПредставление, НаправлениеСдвига = 1)
	ИмяЭлемента = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		ШаблонИмени, "", ?(НаправлениеСдвига > 0, "СдвинутьПериодВперед", "СдвинутьПериодНазад"));
	
	Команда = Форма.Команды.Найти(ИмяЭлемента);
	Если Команда = Неопределено Тогда 
		Команда = Форма.Команды.Добавить(ИмяЭлемента);
	КонецЕсли;
	
	Если НаправлениеСдвига > 0 Тогда 
		Команда.Действие = "Подключаемый_СдвинутьПериодВперед";
		Команда.Заголовок = ">";
		Команда.Подсказка = НСтр("ru = 'Сдвинуть вперед'");
	Иначе
		Команда.Действие = "Подключаемый_СдвинутьПериодНазад";
		Команда.Заголовок = "<";
		Команда.Подсказка = НСтр("ru = 'Сдвинуть назад'");
	КонецЕсли;
	
	Кнопка = Форма.Элементы.Найти(ИмяЭлемента);
	Если Кнопка = Неопределено Тогда 
		Кнопка = Форма.Элементы.Добавить(ИмяЭлемента, Тип("КнопкаФормы"), Группа);
	КонецЕсли;
	Кнопка.ИмяКоманды = ИмяЭлемента;
	Кнопка.ОтображениеФигуры = ОтображениеФигурыКнопки.ПриАктивности;
	Кнопка.Шрифт = Метаданные.ЭлементыСтиля.ВажнаяНадписьШрифт.Значение;
	Кнопка.Видимость = Не ЭтоСтандартноеПредставление;
КонецПроцедуры

Процедура ДобавитьКомандуВыбораПериода(Форма, Группа, ШаблонИмени, Период, ЭтоСтандартноеПредставление)
	ИмяЭлемента = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонИмени, "", "ВыбратьПериод");
	
	Команда = Форма.Команды.Найти(ИмяЭлемента);
	Если Команда = Неопределено Тогда 
		Команда = Форма.Команды.Добавить(ИмяЭлемента);
	КонецЕсли;
	Команда.Действие = "Подключаемый_ВыбратьПериод";
	Команда.Заголовок = НСтр("ru = 'Выбрать период...'");
	Команда.Подсказка = Команда.Заголовок;
	Команда.Отображение = ОтображениеКнопки.Картинка;
	Команда.Картинка = БиблиотекаКартинок.ПолеВводаВыбрать;
	
	ИмяГруппыКнопки = СтрЗаменить(ИмяЭлемента, "ВыбратьПериод", "ГруппаВыбратьПериод");
	ГруппаКнопки = ГруппаЭлементовФормыНастроек(Форма, Группа, ИмяГруппыКнопки);
	ГруппаКнопки.ГоризонтальноеПоложениеПодчиненных = ГоризонтальноеПоложениеЭлемента.Центр;
	
	Кнопка = Форма.Элементы.Найти(ИмяЭлемента);
	Если Кнопка = Неопределено Тогда 
		Кнопка = Форма.Элементы.Добавить(ИмяЭлемента, Тип("КнопкаФормы"), ГруппаКнопки);
	КонецЕсли;
	Кнопка.ИмяКоманды = ИмяЭлемента;
	
	УстановитьСвойстваКнопкиВыбораПериода(ГруппаКнопки, Период, ЭтоСтандартноеПредставление);
КонецПроцедуры

Процедура УстановитьСвойстваКнопкиВыбораПериода(ЭлементПериода, Период, ЭтоСтандартноеПредставление)
	Если ТипЗнч(ЭлементПериода) <> Тип("ГруппаФормы")
		Или ЭлементПериода.ПодчиненныеЭлементы.Количество() = 0
		Или СтрНайти(ЭлементПериода.Имя, "ВыбратьПериод") = 0 Тогда 
		
		Возврат;
	КонецЕсли;
	
	Кнопка = ЭлементПериода.ПодчиненныеЭлементы[0];
	Кнопка.Заголовок = СтроковыеФункции.ПредставлениеПериодаВТексте(Период.ДатаНачала, Период.ДатаОкончания);
	Кнопка.Шрифт = Метаданные.ЭлементыСтиля.ВажнаяНадписьШрифт.Значение;
	
	Если ЭтоСтандартноеПредставление Тогда 
		Кнопка.Ширина = 3;
		Кнопка.Отображение = ОтображениеКнопки.Картинка;
		Кнопка.Картинка = БиблиотекаКартинок.ПолеВводаВыбрать;
		Кнопка.ОтображениеФигуры = ОтображениеФигурыКнопки.Авто;
	Иначе
		ЭлементПериода.Ширина = 15;
		
		Кнопка.Отображение = ОтображениеКнопки.Текст;
		Кнопка.ОтображениеФигуры = ОтображениеФигурыКнопки.Нет;
	КонецЕсли;
КонецПроцедуры

// Устанавливает значения свойствам стандартного периода: ДатаНачала, ДатаОкончания
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//         - РасширениеУправляемойФормыДляОтчета:
//     * Элементы - ВсеЭлементыФормы
//     * Отчет - ОтчетОбъект
//   Индекс - Число
//
// Возвращаемое значение:
//   СтандартныйПериод
//
Функция ИнициализироватьПериод(Форма, Индекс)
	ПользовательскиеНастройки = Форма.Отчет.КомпоновщикНастроек.ПользовательскиеНастройки;
	ЭлементНастройки = ПользовательскиеНастройки.Элементы[Индекс];
	
	Путь = Форма.ПутьКДаннымЭлементов.ПоИндексу[Индекс];
	Если ТипЗнч(ЭлементНастройки) = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
		Период = ЭлементНастройки.Значение;
	Иначе // Элемент отбора.
		Период = ЭлементНастройки.ПравоеЗначение;
	КонецЕсли;
	
	Форма[Путь] = Период;
	
	Возврат Период;
КонецФункции

// Вывод списков элементов формы настроек

Процедура ВывестиСпискиНастроек(Форма, ЭлементыНастроек, ОписаниеНастроек, ИменаРеквизитов)
	Поиск = Новый Структура("ЭтоСписок, СвойствоНастройки", Истина, "Значение");
	НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
	Если НайденныеЭлементы.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	СвязанныеЭлементы = ЭлементыНастроек.Скопировать(Новый Структура("ЭтоСписок, СвойствоНастройки", Истина, "Использование"));
	
	Для Каждого Элемент Из НайденныеЭлементы Цикл 
		СвязанныйЭлемент = СвязанныеЭлементы.Найти(Элемент.ИндексНастройки, "ИндексНастройки");
		Если СвязанныйЭлемент <> Неопределено Тогда
			СвязанноеПоле = СвязанныйЭлемент.Поле;
			Если ТипЗнч(СвязанноеПоле) = Тип("ПолеФормы") И СвязанноеПоле.Вид = ВидПоляФормы.ПолеФлажка Тогда
				СвязанноеПоле.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Право;
			КонецЕсли;
		КонецЕсли;
		
		Элемент.Поле.Видимость = Ложь;
		Описание = ОписаниеНастроек.Найти(Элемент.ИндексНастройки, "ИндексНастройки");
		
		ИмяСписка = Форма.ПутьКДаннымЭлементов.ПоИндексу[Элемент.ИндексНастройки];
		
		ДобавитьЭлементыСписка(Форма, Элемент, Описание, ИмяСписка, ИменаРеквизитов);
		ДобавитьКомандыСписка(Форма, Элемент, ЭлементыНастроек, ИмяСписка);
	КонецЦикла;
КонецПроцедуры

// Создает элементы формы типа ТаблицаФормы, ссылающиеся на реквизит типа СписокЗначений
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//         - РасширениеУправляемойФормыДляОтчета:
//     * Отчет - ОтчетОбъект
//   ЭлементНастройки - СтрокаТаблицыЗначений
//   ОписаниеЭлементаНастройки - СтрокаТаблицыЗначений
//                             - Неопределено
//   ИмяСписка - Строка
//   ИменаРеквизитов - Структура:
//   * Сгенерированных - Структура
//   * Предопределенных - Структура
//
Процедура ДобавитьЭлементыСписка(Форма, ЭлементНастройки, ОписаниеЭлементаНастройки, ИмяСписка, ИменаРеквизитов)
	Элементы = Форма.Элементы; 
	Поле = ЭлементНастройки.Поле; // ПолеФормы
	
	ИменаРеквизитовПредопределенных = ИменаРеквизитов.Предопределенных.Список;
	
	Если ИменаРеквизитовПредопределенных.Найти(ИмяСписка) = Неопределено Тогда 
		Список = Элементы.Добавить(ИмяСписка, Тип("ТаблицаФормы"), Поле.Родитель);
		Список.ПутьКДанным = ИмяСписка;
		Список.ПоложениеКоманднойПанели = ПоложениеКоманднойПанелиЭлементаФормы.Нет;
		Список.Высота = 3;
		Список.УстановитьДействие("ПриИзменении", "Подключаемый_Список_ПриИзменении");
		Список.УстановитьДействие("ПередНачаломДобавления", "Подключаемый_Список_ПередНачаломДобавления");
		Список.УстановитьДействие("ПередНачаломИзменения", "Подключаемый_Список_ПередНачаломИзменения");
		Список.УстановитьДействие("ОбработкаВыбора", "Подключаемый_Список_ОбработкаВыбора");
		
		ПоляСписка = Элементы.Добавить(Список.Имя + "Колонки", Тип("ГруппаФормы"), Список);
		ПоляСписка.Вид = ВидГруппыФормы.ГруппаКолонок;
		ПоляСписка.Группировка = ГруппировкаКолонок.ВЯчейке;
		ПоляСписка.Заголовок = НСтр("ru = 'Поля'");
		ПоляСписка.ОтображатьЗаголовок = Ложь;
		
		ПолеПометки = Элементы.Добавить(ИмяСписка + "Пометка", Тип("ПолеФормы"), ПоляСписка);
		ПолеПометки.Вид = ВидПоляФормы.ПолеФлажка;
		ПолеПометки.ПутьКДанным = ИмяСписка + ".Пометка";
		ПолеПометки.РежимРедактирования = РежимРедактированияКолонки.Непосредственно;
		ПолеПометки.УстановитьДействие("ПриИзменении", "Подключаемый_ПометкаЭлементаСписка_ПриИзменении");
		
		ПолеЗначения = Элементы.Добавить(ИмяСписка + "Значение", Тип("ПолеФормы"), ПоляСписка);
		ПолеЗначения.Вид = ВидПоляФормы.ПолеВвода;
		ПолеЗначения.ПутьКДанным = ИмяСписка + ".Значение";
		ПолеЗначения.УстановитьДействие("ПриИзменении", "Подключаемый_ЭлементСписка_ПриИзменении");
		ПолеЗначения.УстановитьДействие("НачалоВыбора", "Подключаемый_ЭлементСписка_НачалоВыбора");
	Иначе
		Список = Элементы.Найти(ИмяСписка);
		Список.Видимость = Истина;
		
		ПоляСписка = Элементы.Найти(Список.Имя + "Колонки");
		ПолеЗначения = Элементы.Найти(Список.Имя + "Значение");
		
		Элементы.Переместить(Список, Поле.Родитель);
	КонецЕсли;
	
	Список.Заголовок = Поле.Заголовок;
	
	Свойства = "ДоступныеТипы, ОграничениеТипа, АвтоОтметкаНезаполненного, СвязиПараметровВыбора, СвязьПоТипу";
	ЗаполнитьЗначенияСвойств(ПолеЗначения, Поле, Свойства);
	
	ОбщегоНазначенияКлиентСервер.ДополнитьСписок(ПолеЗначения.СписокВыбора, Поле.СписокВыбора, Ложь, Истина);
	
	ПараметрыРедактирования = Новый Структура("БыстрыйВыбор, ВыборГруппИЭлементов");
	Если ОписаниеЭлементаНастройки.ОписаниеНастройки <> Неопределено Тогда 
		ЗаполнитьЗначенияСвойств(ПараметрыРедактирования, ОписаниеЭлементаНастройки.ОписаниеНастройки);
	КонецЕсли;
	
	ПолеЗначения.БыстрыйВыбор = ПараметрыРедактирования.БыстрыйВыбор;
	
	Условие = ОтчетыКлиентСервер.УсловиеЭлементаНастройки(
		ОписаниеЭлементаНастройки.ЭлементНастройки, ОписаниеЭлементаНастройки.ОписаниеНастройки);
	ПолеЗначения.ВыборГруппИЭлементов = ОтчетыКлиентСервер.ЗначениеТипаГруппыИЭлементы(
		ПараметрыРедактирования.ВыборГруппИЭлементов, Условие);
	
	ПолеЗначения.ПараметрыВыбора = ОтчетыКлиентСервер.ПараметрыВыбора(
		ОписаниеЭлементаНастройки.Настройки,
		Форма.Отчет.КомпоновщикНастроек.ПользовательскиеНастройки.Элементы,
		ОписаниеЭлементаНастройки.ЭлементНастройки);
	
	ИнициализироватьСписок(Форма, ЭлементНастройки.ИндексНастройки, ПолеЗначения, ОписаниеЭлементаНастройки.ЭлементНастройки);
	
	Если Поле.СписокВыбора.Количество() > 0 Тогда 
		Список.ИзменятьСоставСтрок = Ложь;
		ПолеЗначения.ТолькоПросмотр = Истина;
	КонецЕсли;
КонецПроцедуры

Процедура ДобавитьКомандыСписка(Форма, ЭлементНастройки, ЭлементыНастроек, ИмяСписка)
	Элементы = Форма.Элементы; 
	
	Поиск = Новый Структура("СвойствоНастройки, ИндексНастройки", "Использование");
	Поиск.ИндексНастройки = ЭлементНастройки.ИндексНастройки;
	
	ПолеЗаголовка = ЭлементыНастроек.НайтиСтроки(Поиск)[0].Поле;
	ГруппаЗаголовка = ПолеЗаголовка.Родитель;
	ГруппаЗаголовка.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	
	ГруппаСписка = ГруппаЗаголовка.Родитель;
	ГруппаСписка.Отображение = ОтображениеОбычнойГруппы.ОбычноеВыделение;
	
	Если Не Элементы[ИмяСписка].ИзменятьСоставСтрок Тогда 
		Возврат;
	КонецЕсли;
	
	ИмяЭлемента = ИмяСписка + "Отступ";
	Отступ = Элементы.Найти(ИмяЭлемента);
	Если Отступ = Неопределено Тогда 
		Отступ = Элементы.Добавить(ИмяЭлемента, Тип("ДекорацияФормы"), ГруппаЗаголовка);
	ИначеЕсли Отступ.Родитель <> ГруппаЗаголовка Тогда 
		Элементы.Переместить(Отступ, ГруппаЗаголовка);
	КонецЕсли;
	Отступ.Вид = ВидДекорацииФормы.Надпись;
	Отступ.Заголовок = "     ";
	Отступ.РастягиватьПоГоризонтали = Истина;
	Отступ.АвтоМаксимальнаяШирина = Ложь;
	Отступ.Видимость = Истина;
	
	ИмяКоманды = ИмяСписка + "Подбор";
	ЗаголовокКоманды = НСтр("ru = 'Подбор'");
	ДобавитьКомандуСписка(Форма, ГруппаЗаголовка, ИмяКоманды, ЗаголовокКоманды, "Подключаемый_Список_Подбор");
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЗагрузкаДанныхИзФайла") Тогда 
		Возврат;
	КонецЕсли;
	
	ИмяКоманды = ИмяСписка + "ВставитьИзБуфера";
	ЗаголовокКоманды = НСтр("ru = 'Вставить из буфера обмена...'");
	ДобавитьКомандуСписка(Форма, ГруппаЗаголовка, ИмяКоманды, ЗаголовокКоманды,
		"Подключаемый_Список_ВставитьИзБуфера", БиблиотекаКартинок.ВставитьИзБуфераОбмена);
КонецПроцедуры

Процедура ДобавитьКомандуСписка(Форма, Родитель, ИмяКоманды, Заголовок, Действие, Картинка = Неопределено)
	Команда = Форма.Команды.Найти(ИмяКоманды);
	Если Команда = Неопределено Тогда 
		Команда = Форма.Команды.Добавить(ИмяКоманды);
	КонецЕсли;
	Команда.Действие = Действие;
	Команда.Заголовок = Заголовок;
	Команда.Подсказка = Заголовок;
	
	Если Картинка = Неопределено Тогда 
		Команда.Отображение = ОтображениеКнопки.Текст;
	Иначе
		Команда.Отображение = ОтображениеКнопки.Картинка;
		Команда.Картинка = БиблиотекаКартинок.ВставитьИзБуфераОбмена;
	КонецЕсли;
	
	Кнопка = Форма.Элементы.Найти(ИмяКоманды);
	Если Кнопка = Неопределено Тогда 
		Кнопка = Форма.Элементы.Добавить(ИмяКоманды, Тип("КнопкаФормы"), Родитель);
	ИначеЕсли Кнопка.Родитель <> Родитель Тогда 
		Форма.Элементы.Переместить(Кнопка, Родитель);
	КонецЕсли;
	Кнопка.ИмяКоманды = ИмяКоманды;
	Кнопка.Вид = ВидКнопкиФормы.Гиперссылка;
	Кнопка.Видимость = Истина;
КонецПроцедуры

Процедура ИнициализироватьСписок(Форма, Индекс, Поле, ЭлементНастройки)
	ПользовательскиеНастройки = Форма.Отчет.КомпоновщикНастроек.ПользовательскиеНастройки;
	ЭлементНастройки = ПользовательскиеНастройки.Элементы[Индекс];
	
	Путь = Форма.ПутьКДаннымЭлементов.ПоИндексу[Индекс];
	Список = Форма[Путь];
	Список.ТипЗначения = Поле.ДоступныеТипы;
	Список.Очистить();
	
	ИмяПоляЗначения = "ПравоеЗначение";
	Если ТипЗнч(ЭлементНастройки) = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
		ИмяПоляЗначения = "Значение";
	КонецЕсли;
	
	ВыбранныеЗначения = ОтчетыКлиентСервер.ЗначенияСписком(ЭлементНастройки[ИмяПоляЗначения]);
	Если ВыбранныеЗначения.Количество() > 0 Тогда 
		ЭлементНастройки[ИмяПоляЗначения] = ВыбранныеЗначения;
	Иначе
		ВыбранныеЗначения = ОтчетыКлиентСервер.ЗначенияСписком(ЭлементНастройки[ИмяПоляЗначения]);
		Если ВыбранныеЗначения.Количество() > 0 Тогда 
			// При выполнении метода СоздатьЭлементыФормыПользовательскихНастроек()
			// сбрасывается значение пользовательской настройки.
			ЭлементНастройки[ИмяПоляЗначения] = ВыбранныеЗначения;
		КонецЕсли;
	КонецЕсли;
	
	ДоступныеЗначения = Новый СписокЗначений;
	Если Поле.БыстрыйВыбор = Истина Тогда 
		ПараметрыСписка = Новый Структура("ПараметрыВыбора, ОписаниеТипов, ВыборГруппИЭлементов, Отбор");
		ЗаполнитьЗначенияСвойств(ПараметрыСписка, Поле);
		ПараметрыСписка.ОписаниеТипов = Поле.ДоступныеТипы;
		ПараметрыСписка.Отбор = Новый Структура;
		
		ДоступныеЗначения = ЗначенияДляВыбора(ПараметрыСписка);
	КонецЕсли;
	
	Если ДоступныеЗначения.Количество() = 0 Тогда 
		ДоступныеЗначения = Поле.СписокВыбора;
	КонецЕсли;
	
	ОбщегоНазначенияКлиентСервер.ДополнитьСписок(Список, ДоступныеЗначения, Ложь, Истина);
	ОбщегоНазначенияКлиентСервер.ДополнитьСписок(Список, ВыбранныеЗначения, Ложь, Истина);
	
	Для Каждого ЭлементСписка Из Список Цикл 
		Если Не ЗначениеЗаполнено(ЭлементСписка.Значение) Тогда 
			Продолжить;
		КонецЕсли;
		
		НайденныйЭлемент = ДоступныеЗначения.НайтиПоЗначению(ЭлементСписка.Значение);
		Если НайденныйЭлемент <> Неопределено Тогда 
			ЭлементСписка.Представление = НайденныйЭлемент.Представление;
		КонецЕсли;
		
		НайденныйЭлемент = ВыбранныеЗначения.НайтиПоЗначению(ЭлементСписка.Значение);
		ЭлементСписка.Пометка = (НайденныйЭлемент <> Неопределено);
	КонецЦикла;
	
	ПолеСписка = Форма.Элементы[Путь]; // ТаблицаФормы
	Если ЭлементНастройки.Использование Тогда 
		ПолеСписка.ЦветТекста = Новый Цвет;
	Иначе
		ПолеСписка.ЦветТекста = Метаданные.ЭлементыСтиля.ТекстЗапрещеннойЯчейкиЦвет.Значение;
	КонецЕсли;
КонецПроцедуры

// Вывод значений как поля флажков.

Процедура ВывестиЗначенияКакПоляФлажков(Форма, ЭлементыНастроек, ИменаРеквизитов)
	Поиск = Новый Структура("ЭтоЗначениеКакФлажок, СвойствоНастройки", Истина, "Использование");
	НайденныеЭлементы = ЭлементыНастроек.НайтиСтроки(Поиск);
	Если НайденныеЭлементы.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	Элементы = Форма.Элементы;
	ИменаРеквизитовПредопределенных = ИменаРеквизитов.Предопределенных.Флажок;
	
	Для Каждого Элемент Из НайденныеЭлементы Цикл 
		Поле = Элемент.Поле;
		
		ИмяРеквизита = Форма.ПутьКДаннымЭлементов.ПоИндексу[Элемент.ИндексНастройки];
		Если ИменаРеквизитовПредопределенных.Найти(ИмяРеквизита) = Неопределено Тогда 
			ПолеФлажка = Элементы.Добавить(ИмяРеквизита, Тип("ПолеФормы"), Поле.Родитель);
			ПолеФлажка.Вид = ВидПоляФормы.ПолеФлажка;
			ПолеФлажка.ПутьКДанным = ИмяРеквизита;
			ПолеФлажка.УстановитьДействие("ПриИзменении", "Подключаемый_ЭлементНастройки_ПриИзменении");
		Иначе
			ПолеФлажка = Элементы.Найти(ИмяРеквизита);
			Элементы.Переместить(ПолеФлажка, Поле.Родитель);
			ПолеФлажка.Видимость = Истина;
		КонецЕсли;
		
		ПолеФлажка.Заголовок = Поле.Заголовок;
		ПолеФлажка.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
		Элемент.Поле = ПолеФлажка;
		
		ИнициализироватьФлажок(Форма, Элемент.ИндексНастройки);
	КонецЦикла;
КонецПроцедуры

// Устанавливает значение флажка.
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//         - РасширениеУправляемойФормыДляОтчета:
//     * Отчет - ОтчетОбъект
//   Индекс - Число
//
Процедура ИнициализироватьФлажок(Форма, Индекс)
	ПользовательскиеНастройки = Форма.Отчет.КомпоновщикНастроек.ПользовательскиеНастройки;
	ЭлементНастройки = ПользовательскиеНастройки.Элементы[Индекс];
	
	Путь = Форма.ПутьКДаннымЭлементов.ПоИндексу[Индекс];
	Если ТипЗнч(ЭлементНастройки) = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда 
		Форма[Путь] = ЭлементНастройки.Значение;
	Иначе // Элемент отбора.
		Форма[Путь] = ЭлементНастройки.ПравоеЗначение;
	КонецЕсли;
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Сохранение состояния формы

// Запоминает состояние формы.
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//   ИмяТаблицы - Строка
//   КлючевыеКолонки - Строка
// 
// Возвращаемое значение:
//   Структура:
//   * Текущая - Неопределено
//   * Выделенные - Массив
//
Функция ЗапомнитьВыделенныеСтроки(Форма, ИмяТаблицы, КлючевыеКолонки) Экспорт
	ТаблицаРеквизит = Форма[ИмяТаблицы];
	ТаблицаЭлемент = Форма.Элементы.Найти(ИмяТаблицы); // ТаблицаФормы
	
	Результат = Новый Структура;
	Результат.Вставить("Выделенные", Новый Массив);
	Результат.Вставить("Текущая", Неопределено);
	
	ТекущаяИдентификатор = ТаблицаЭлемент.ТекущаяСтрока;
	Если ТекущаяИдентификатор <> Неопределено Тогда
		СтрокаТаблицы = ТаблицаРеквизит.НайтиПоИдентификатору(ТекущаяИдентификатор);
		Если СтрокаТаблицы <> Неопределено Тогда
			ДанныеСтроки = Новый Структура(КлючевыеКолонки);
			ЗаполнитьЗначенияСвойств(ДанныеСтроки, СтрокаТаблицы);
			Результат.Текущая = ДанныеСтроки;
		КонецЕсли;
	КонецЕсли;
	
	ВыделенныеСтроки = ТаблицаЭлемент.ВыделенныеСтроки;
	Если ВыделенныеСтроки <> Неопределено Тогда
		Для Каждого ВыделеннаяИдентификатор Из ВыделенныеСтроки Цикл
			Если ВыделеннаяИдентификатор = ТекущаяИдентификатор Тогда
				Продолжить;
			КонецЕсли;
			СтрокаТаблицы = ТаблицаРеквизит.НайтиПоИдентификатору(ВыделеннаяИдентификатор);
			Если СтрокаТаблицы <> Неопределено Тогда
				ДанныеСтроки = Новый Структура(КлючевыеКолонки);
				ЗаполнитьЗначенияСвойств(ДанныеСтроки, СтрокаТаблицы);
				Результат.Выделенные.Добавить(ДанныеСтроки);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

// Восстанавливает состояние формы.
// 
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//   ИмяТаблицы - Строка
//   КлючевыеКолонки - Строка
// 
Процедура ВосстановитьВыделенныеСтроки(Форма, ИмяТаблицы, СтрокиТаблицы) Экспорт
	ТаблицаРеквизит = Форма[ИмяТаблицы];
	ТаблицаЭлемент = Форма.Элементы[ИмяТаблицы]; // ТаблицаФормы
	
	ТаблицаЭлемент.ВыделенныеСтроки.Очистить();
	
	Если СтрокиТаблицы.Текущая <> Неопределено Тогда
		Найденные = ОтчетыКлиентСервер.НайтиСтрокиТаблицы(ТаблицаРеквизит, СтрокиТаблицы.Текущая);
		Если Найденные <> Неопределено И Найденные.Количество() > 0 Тогда
			Для Каждого СтрокаТаблицы Из Найденные Цикл
				Если СтрокаТаблицы <> Неопределено Тогда
					Идентификатор = СтрокаТаблицы.ПолучитьИдентификатор();
					ТаблицаЭлемент.ТекущаяСтрока = Идентификатор;
					Прервать;
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	Для Каждого ДанныеСтроки Из СтрокиТаблицы.Выделенные Цикл
		Найденные = ОтчетыКлиентСервер.НайтиСтрокиТаблицы(ТаблицаРеквизит, ДанныеСтроки);
		Если Найденные <> Неопределено И Найденные.Количество() > 0 Тогда
			Для Каждого СтрокаТаблицы Из Найденные Цикл
				Если СтрокаТаблицы <> Неопределено Тогда
					ТаблицаЭлемент.ВыделенныеСтроки.Добавить(СтрокаТаблицы.ПолучитьИдентификатор());
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Отчет пустой

// Проверяет наличие внешних наборов данных.
//
// Параметры:
//   НаборыДанных - НаборыДанныхМакетаКомпоновкиДанных - коллекция проверяемых наборов данных.
//
// Возвращаемое значение: 
//   Булево - Истина, если есть внешние наборы данных.
//
Функция ЕстьВнешнийНаборДанных(НаборыДанных)
	
	Для Каждого НаборДанных Из НаборыДанных Цикл
		
		Если ТипЗнч(НаборДанных) = Тип("НаборДанныхОбъектМакетаКомпоновкиДанных") Тогда
			
			Возврат Истина;
			
		ИначеЕсли ТипЗнч(НаборДанных) = Тип("НаборДанныхОбъединениеМакетаКомпоновкиДанных") Тогда
			
			Если ЕстьВнешнийНаборДанных(НаборДанных.Элементы) Тогда
				
				Возврат Истина;
				
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Параметры выбора

Функция ЗначенияДляВыбора(ПараметрыНастройки, ТипИлиТипы = Неопределено) Экспорт
	ПараметрыПолученияДанныхВыбора = Новый Структура("Отбор, ВыборГруппИЭлементов");
	ЗаполнитьЗначенияСвойств(ПараметрыПолученияДанныхВыбора, ПараметрыНастройки);
	ДополнитьСтруктуруИзПараметровВыбора(ПараметрыПолученияДанныхВыбора, ПараметрыНастройки.ПараметрыВыбора);
	
	ЗначенияДляВыбора = Новый СписокЗначений;
	Если ТипЗнч(ТипИлиТипы) = Тип("Тип") Тогда
		Типы = Новый Массив;
		Типы.Добавить(ТипИлиТипы);
	ИначеЕсли ТипЗнч(ТипИлиТипы) = Тип("Массив") Тогда
		Типы = ТипИлиТипы;
	Иначе
		Типы = ПараметрыНастройки.ОписаниеТипов.Типы();
	КонецЕсли;
	
	Для Каждого Тип Из Типы Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
		Если ОбъектМетаданных = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Менеджер = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя());
		
		СписокВыбора = Менеджер.ПолучитьДанныеВыбора(ПараметрыПолученияДанныхВыбора);
		Для Каждого ЭлементСписка Из СписокВыбора Цикл
			ЗначениеДляВыбора = ЗначенияДляВыбора.Добавить();
			ЗаполнитьЗначенияСвойств(ЗначениеДляВыбора, ЭлементСписка);
			
			// Для перечислений значения возвращаются в виде структуры со свойством Значение.
			ЗначениеПеречисления = Неопределено;
			Если ТипЗнч(ЗначениеДляВыбора.Значение) = Тип("Структура") 
				И ЗначениеДляВыбора.Значение.Свойство("Значение", ЗначениеПеречисления) Тогда
				ЗначениеДляВыбора.Значение = ЗначениеПеречисления;
			КонецЕсли;	
				
		КонецЦикла;
	КонецЦикла;
	Возврат ЗначенияДляВыбора;
КонецФункции

Процедура ДополнитьСтруктуруИзПараметровВыбора(Структура, МассивПараметровВыбора)
	Для Каждого ПараметрВыбора Из МассивПараметровВыбора Цикл
		ТекущаяСтруктура = Структура;
		МассивСтрок = СтрРазделить(ПараметрВыбора.Имя, ".");
		Количество = МассивСтрок.Количество();
		Если Количество > 1 Тогда
			Для Индекс = 0 По Количество-2 Цикл
				Ключ = МассивСтрок[Индекс];
				Если ТекущаяСтруктура.Свойство(Ключ) И ТипЗнч(ТекущаяСтруктура[Ключ]) = Тип("Структура") Тогда
					ТекущаяСтруктура = ТекущаяСтруктура[Ключ];
				Иначе
					ТекущаяСтруктура.Вставить(Ключ, Новый Структура);
					ТекущаяСтруктура = ТекущаяСтруктура[Ключ];
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		Ключ = МассивСтрок[Количество-1];
		ТекущаяСтруктура.Вставить(Ключ, ПараметрВыбора.Значение);
	КонецЦикла;
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Схема компоновки данных

// Добавляет выбранное поле компоновки данных.
//
// Параметры:
//   Куда - КомпоновщикНастроекКомпоновкиДанных
//        - НастройкиКомпоновкиДанных
//        - ВыбранныеПоляКомпоновкиДанных -
//       Коллекция в которую требуется добавить выбранное поле.
//   ИмяИлиПолеКД - Строка
//                - ПолеКомпоновкиДанных - имя поля.
//   Заголовок    - Строка - представление поля.
//
// Возвращаемое значение:
//   ВыбранноеПолеКомпоновкиДанных - добавленное выбранное поле.
//
Функция ДобавитьВыбранноеПоле(Куда, ИмяИлиПолеКД, Заголовок = "") Экспорт
	
	Если ТипЗнч(Куда) = Тип("КомпоновщикНастроекКомпоновкиДанных") Тогда
		ВыбранныеПоляКД = Куда.Настройки.Выбор;
	ИначеЕсли ТипЗнч(Куда) = Тип("НастройкиКомпоновкиДанных") Тогда
		ВыбранныеПоляКД = Куда.Выбор;
	Иначе
		ВыбранныеПоляКД = Куда;
	КонецЕсли;
	
	Если ТипЗнч(ИмяИлиПолеКД) = Тип("Строка") Тогда
		ПолеКД = Новый ПолеКомпоновкиДанных(ИмяИлиПолеКД);
	Иначе
		ПолеКД = ИмяИлиПолеКД;
	КонецЕсли;
	
	ВыбранноеПолеКД = ВыбранныеПоляКД.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
	ВыбранноеПолеКД.Поле = ПолеКД;
	Если Заголовок <> "" Тогда
		ВыбранноеПолеКД.Заголовок = Заголовок;
	КонецЕсли;
	
	Возврат ВыбранноеПолеКД;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Контекстные варианты

Процедура ДобавитьВариантыКонтекста(Отчет, Варианты, ВариантыКонтекста) Экспорт 
	
	Если ВариантыКонтекста.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	ОтсутствующиеВарианты = Новый Массив;
	
	Для Каждого ВариантКонтекста Из ВариантыКонтекста Цикл 
		
		Если Варианты.Найти(ВариантКонтекста.Значение, "КлючВарианта") = Неопределено Тогда 
			ОтсутствующиеВарианты.Добавить(ВариантКонтекста.Значение);
		КонецЕсли;
		
	КонецЦикла;
	
	Если ОтсутствующиеВарианты.Количество() = 0 Тогда 
		Возврат;
	КонецЕсли;
	
	Запрос = Новый Запрос(
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	ВариантыОтчетов.*,
	|	ВариантыОтчетов.Представление КАК Наименование
	|ИЗ
	|	Справочник.ВариантыОтчетов КАК ВариантыОтчетов
	|ГДЕ
	|	ВариантыОтчетов.Отчет = &Отчет
	|	И ВариантыОтчетов.КлючВарианта В (&ОтсутствующиеВарианты)");
	
	Запрос.УстановитьПараметр("Отчет", Отчет);
	Запрос.УстановитьПараметр("ОтсутствующиеВарианты", ОтсутствующиеВарианты);
	
	Вариант = Запрос.Выполнить().Выбрать();
	
	Пока Вариант.Следующий() Цикл
		ЗаполнитьЗначенияСвойств(Варианты.Добавить(), Вариант);
	КонецЦикла;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Прочее

Функция РасширенноеОписаниеТипов(ИсходноеОписаниеТипов, ПривестиКФорме, ПараметрыПодбора = Неопределено) Экспорт
	Результат = Новый Структура;
	Результат.Вставить("СодержитТипТип",        Ложь);
	Результат.Вставить("СодержитТипДата",       Ложь);
	Результат.Вставить("СодержитТипБулево",     Ложь);
	Результат.Вставить("СодержитТипСтрока",     Ложь);
	Результат.Вставить("СодержитТипЧисло",      Ложь);
	Результат.Вставить("СодержитТипПериод",     Ложь);
	Результат.Вставить("СодержитТипУИД",        Ложь);
	Результат.Вставить("СодержитТипХранилище",  Ложь);
	Результат.Вставить("СодержитОбъектныеТипы", Ложь);
	Результат.Вставить("ОграниченнойДлины",     Истина);
	
	Результат.Вставить("КоличествоТипов",            0);
	Результат.Вставить("КоличествоПримитивныхТипов", 0);
	Результат.Вставить("ОбъектныеТипы", Новый Массив);
	
	Если ПривестиКФорме Тогда
		ДобавляемыеТипы = Новый Массив;
		ВычитаемыеТипы = Новый Массив;
		Результат.Вставить("ОписаниеТиповИсходное", ИсходноеОписаниеТипов);
		Результат.Вставить("ОписаниеТиповДляФормы", ИсходноеОписаниеТипов);
	КонецЕсли;
	
	Если ИсходноеОписаниеТипов = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	МассивТипов = ИсходноеОписаниеТипов.Типы();
	Для Каждого Тип Из МассивТипов Цикл
		Если Тип = Тип("Null") Тогда 
			ВычитаемыеТипы.Добавить(Тип);
			Продолжить;
		КонецЕсли;
		
		Если Тип = Тип("ПолеКомпоновкиДанных") Тогда
			Если ПривестиКФорме Тогда
				ВычитаемыеТипы.Добавить(Тип);
			КонецЕсли;
			Продолжить;
		КонецЕсли;
		
		МетаданныеНастройки = Метаданные.НайтиПоТипу(Тип);
		Если МетаданныеНастройки <> Неопределено Тогда 
			Если ОбщегоНазначения.ОбъектМетаданныхДоступенПоФункциональнымОпциям(МетаданныеНастройки) Тогда
				Если ТипЗнч(ПараметрыПодбора) = Тип("Соответствие") Тогда 
					ПараметрыПодбора.Вставить(Тип, МетаданныеНастройки.ПолноеИмя() + ".ФормаВыбора");
				КонецЕсли;
			Иначе // Объект недоступен.
				Если ПривестиКФорме Тогда
					ВычитаемыеТипы.Добавить(Тип);
				КонецЕсли;
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		Результат.КоличествоТипов = Результат.КоличествоТипов + 1;
		
		Если Тип = Тип("Тип") Тогда
			Результат.СодержитТипТип = Истина;
		ИначеЕсли Тип = Тип("Дата") Тогда
			Результат.СодержитТипДата = Истина;
			Результат.КоличествоПримитивныхТипов = Результат.КоличествоПримитивныхТипов + 1;
		ИначеЕсли Тип = Тип("Булево") Тогда
			Результат.СодержитТипБулево = Истина;
			Результат.КоличествоПримитивныхТипов = Результат.КоличествоПримитивныхТипов + 1;
		ИначеЕсли Тип = Тип("Число") Тогда
			Результат.СодержитТипЧисло = Истина;
			Результат.КоличествоПримитивныхТипов = Результат.КоличествоПримитивныхТипов + 1;
		ИначеЕсли Тип = Тип("СтандартныйПериод") Тогда
			Результат.СодержитТипПериод = Истина;
		ИначеЕсли Тип = Тип("Строка") Тогда
			Результат.СодержитТипСтрока = Истина;
			Результат.КоличествоПримитивныхТипов = Результат.КоличествоПримитивныхТипов + 1;
			Если ИсходноеОписаниеТипов.КвалификаторыСтроки.Длина = 0
				И ИсходноеОписаниеТипов.КвалификаторыСтроки.ДопустимаяДлина = ДопустимаяДлина.Переменная Тогда
				Результат.ОграниченнойДлины = Ложь;
			КонецЕсли;
		ИначеЕсли Тип = Тип("УникальныйИдентификатор") Тогда
			Результат.СодержитТипУИД = Истина;
		ИначеЕсли Тип = Тип("ХранилищеЗначения") Тогда
			Результат.СодержитТипХранилище = Истина;
		Иначе
			Результат.СодержитОбъектныеТипы = Истина;
			Результат.ОбъектныеТипы.Добавить(Тип);
		КонецЕсли;
		
	КонецЦикла;
	
	Если ПривестиКФорме
		И (ДобавляемыеТипы.Количество() > 0 Или ВычитаемыеТипы.Количество() > 0) Тогда
		Результат.ОписаниеТиповДляФормы = Новый ОписаниеТипов(ИсходноеОписаниеТипов, ДобавляемыеТипы, ВычитаемыеТипы);
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция ТипНастройкиСтрокой(Тип)
	Если Тип = Тип("НастройкиКомпоновкиДанных") Тогда
		Возврат "Настройки";
	ИначеЕсли Тип = Тип("НастройкиВложенногоОбъектаКомпоновкиДанных") Тогда
		Возврат "НастройкиВложенногоОбъекта";
	
	ИначеЕсли Тип = Тип("ОтборКомпоновкиДанных") Тогда
		Возврат "Отбор";
	ИначеЕсли Тип = Тип("ЭлементОтбораКомпоновкиДанных") Тогда
		Возврат "ЭлементОтбора";
	ИначеЕсли Тип = Тип("ГруппаЭлементовОтбораКомпоновкиДанных") Тогда
		Возврат "ГруппаЭлементовОтбора";
	
	ИначеЕсли Тип = Тип("ЗначениеПараметраНастроекКомпоновкиДанных") Тогда
		Возврат "ЗначениеПараметраНастроек";
	
	ИначеЕсли Тип = Тип("ГруппировкаКомпоновкиДанных") Тогда
		Возврат "Группировка";
	ИначеЕсли Тип = Тип("ПоляГруппировкиКомпоновкиДанных") Тогда
		Возврат "ПоляГруппировки";
	ИначеЕсли Тип = Тип("КоллекцияПолейГруппировкиКомпоновкиДанных") Тогда
		Возврат "КоллекцияПолейГруппировки";
	ИначеЕсли Тип = Тип("ПолеГруппировкиКомпоновкиДанных") Тогда
		Возврат "ПолеГруппировки";
	ИначеЕсли Тип = Тип("АвтоПолеГруппировкиКомпоновкиДанных") Тогда
		Возврат "АвтоПолеГруппировки";
	
	ИначеЕсли Тип = Тип("ВыбранныеПоляКомпоновкиДанных") Тогда
		Возврат "ВыбранныеПоля";
	ИначеЕсли Тип = Тип("ВыбранноеПолеКомпоновкиДанных") Тогда
		Возврат "ВыбранноеПоле";
	ИначеЕсли Тип = Тип("ГруппаВыбранныхПолейКомпоновкиДанных") Тогда
		Возврат "ГруппаВыбранныхПолей";
	ИначеЕсли Тип = Тип("АвтоВыбранноеПолеКомпоновкиДанных") Тогда
		Возврат "АвтоВыбранноеПоле";
	
	ИначеЕсли Тип = Тип("ПорядокКомпоновкиДанных") Тогда
		Возврат "Порядок";
	ИначеЕсли Тип = Тип("ЭлементПорядкаКомпоновкиДанных") Тогда
		Возврат "ЭлементПорядка";
	ИначеЕсли Тип = Тип("АвтоЭлементПорядкаКомпоновкиДанных") Тогда
		Возврат "АвтоЭлементПорядка";
	
	ИначеЕсли Тип = Тип("УсловноеОформлениеКомпоновкиДанных") Тогда
		Возврат "УсловноеОформление";
	ИначеЕсли Тип = Тип("ЭлементУсловногоОформленияКомпоновкиДанных") Тогда
		Возврат "ЭлементУсловногоОформления";
	
	ИначеЕсли Тип = Тип("СтруктураНастроекКомпоновкиДанных") Тогда
		Возврат "СтруктураНастроек";
	ИначеЕсли Тип = Тип("КоллекцияЭлементовСтруктурыНастроекКомпоновкиДанных") Тогда
		Возврат "КоллекцияЭлементовСтруктурыНастроек";
	
	ИначеЕсли Тип = Тип("ТаблицаКомпоновкиДанных") Тогда
		Возврат "Таблица";
	ИначеЕсли Тип = Тип("ГруппировкаТаблицыКомпоновкиДанных") Тогда
		Возврат "ГруппировкаТаблицы";
	ИначеЕсли Тип = Тип("КоллекцияЭлементовСтруктурыТаблицыКомпоновкиДанных") Тогда
		Возврат "КоллекцияЭлементовСтруктурыТаблицы";
	
	ИначеЕсли Тип = Тип("ДиаграммаКомпоновкиДанных") Тогда
		Возврат "Диаграмма";
	ИначеЕсли Тип = Тип("ГруппировкаДиаграммыКомпоновкиДанных") Тогда
		Возврат "ГруппировкаДиаграммы";
	ИначеЕсли Тип = Тип("КоллекцияЭлементовСтруктурыДиаграммыКомпоновкиДанных") Тогда
		Возврат "КоллекцияЭлементовСтруктурыДиаграммы";
	
	ИначеЕсли Тип = Тип("ЗначенияПараметровДанныхКомпоновкиДанных") Тогда
		Возврат "ЗначенияПараметровДанных";
	
	Иначе
		Возврат "";
	КонецЕсли;
КонецФункции

Функция ЗначениеВМассив(Значение) Экспорт
	Если ТипЗнч(Значение) = Тип("Массив") Тогда
		Возврат Значение;
	Иначе
		Массив = Новый Массив;
		Массив.Добавить(Значение);
		Возврат Массив;
	КонецЕсли;
КонецФункции

Функция ПривестиИдентификаторКИмени(Идентификатор) Экспорт
	Возврат СтрЗаменить(СтрЗаменить(Строка(Идентификатор), "-", ""), ".", "_");
КонецФункции

// Находит элемент компоновки данных по полному пути.
//
// Параметры:
//   НастройкиКД - НастройкиКомпоновкиДанных - корневой узел настроек, в который вложен искомый элемент.
//   ПолныйПутьКЭлементу - Строка - полный путь к элементу. Может быть получена в функции ПолныйПутьКЭлементу().
//
// Возвращаемое значение:
//   - НастройкиКомпоновкиДанных
//   - КоллекцияЭлементовСтруктурыНастроекКомпоновкиДанных
//   - ГруппировкаКомпоновкиДанных
//   - КоллекцияЭлементовСтруктурыТаблицыКомпоновкиДанных
//   - ГруппировкаТаблицыКомпоновкиДанных
//   - КоллекцияЭлементовСтруктурыДиаграммыКомпоновкиДанных
//   - ГруппировкаДиаграммыКомпоновкиДанных - найденный узел настроек.
//
Функция ЭлементНастроекПоПолномуПути(Знач Настройки, Знач ПолныйПутьКЭлементу) Экспорт
	Индексы = СтрРазделить(ПолныйПутьКЭлементу, "/", Ложь);
	ЭлементНастроек = Настройки;
	
	Для Каждого Индекс Из Индексы Цикл
		Если Индекс = "Строки" Тогда
			ЭлементНастроек = ЭлементНастроек.Строки;
		ИначеЕсли Индекс = "Колонки" Тогда
			ЭлементНастроек = ЭлементНастроек.Колонки;
		ИначеЕсли Индекс = "Серии" Тогда
			ЭлементНастроек = ЭлементНастроек.Серии;
		ИначеЕсли Индекс = "Точки" Тогда
			ЭлементНастроек = ЭлементНастроек.Точки;
		ИначеЕсли Индекс = "Структура" Тогда
			ЭлементНастроек = ЭлементНастроек.Структура;
		ИначеЕсли Индекс = "Настройки" Тогда
			ЭлементНастроек = ЭлементНастроек.Настройки;
		Иначе
			ЭлементНастроек = ЭлементНастроек[Число(Индекс)];
		КонецЕсли;
	КонецЦикла;
	
	Возврат ЭлементНастроек;
КонецФункции

Процедура УстановитьУсловияОтборов(ПараметрыЗагрузки, КомпоновщикНастроек) Экспорт 
	УсловияОтборов = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыЗагрузки, "УсловияОтборов");
	Если УсловияОтборов = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Настройки = КомпоновщикНастроек.Настройки;
	ПользовательскиеНастройки = КомпоновщикНастроек.ПользовательскиеНастройки;
	
	Для Каждого Условие Из УсловияОтборов Цикл
		ЭлементПользовательскойНастройки = ПользовательскиеНастройки.ПолучитьОбъектПоИдентификатору(Условие.Ключ);
		ЭлементПользовательскойНастройки.ВидСравнения = Условие.Значение;
		
		Если ОтчетыКлиентСервер.ЭтоВидСравненияСписка(ЭлементПользовательскойНастройки.ВидСравнения)
			И ТипЗнч(ЭлементПользовательскойНастройки.ПравоеЗначение) <> Тип("СписокЗначений") Тогда 
			
			ЭлементПользовательскойНастройки.ПравоеЗначение = ОтчетыКлиентСервер.ЗначенияСписком(
				ЭлементПользовательскойНастройки.ПравоеЗначение);
		КонецЕсли;
		
		ЭлементНастройки = ОтчетыКлиентСервер.ПолучитьОбъектПоПользовательскомуИдентификатору(
			Настройки, ЭлементПользовательскойНастройки.ИдентификаторПользовательскойНастройки,, ПользовательскиеНастройки);
		
		ЗаполнитьЗначенияСвойств(ЭлементНастройки, ЭлементПользовательскойНастройки, "ВидСравнения, ПравоеЗначение");
	КонецЦикла;
КонецПроцедуры

Процедура УстановитьДоступныеЗначенияНастроек(Форма, Отчет, КомпоновщикНастроек, ЭлементПользовательскойНастройки, ЭлементОсновнойНастройки, ОписаниеНастройки)
		
	СвойстваНастройки = СвойстваЭлементаПользовательскихНастроек(
	КомпоновщикНастроек, ЭлементПользовательскойНастройки, ЭлементОсновнойНастройки, ОписаниеНастройки);
	
	// Механизмы расширения.
	ИнтеграцияПодсистемБСП.ПриОпределенииПараметровВыбораВариантыОтчетов(Неопределено, СвойстваНастройки);
	
	// Глобальные настройки вывода типов.
	ОтчетыПереопределяемый.ПриОпределенииПараметровВыбора(Неопределено, СвойстваНастройки);
	
	// Локальное переопределение для отчета.
	Если Форма.НастройкиОтчета.События.ПриОпределенииПараметровВыбора Тогда 
		Отчет.ПриОпределенииПараметровВыбора(Форма, СвойстваНастройки);
	КонецЕсли;
	
	// Автоматическое заполнение.
	Если СвойстваНастройки.ЗапросЗначенийВыбора.Текст <> "" Тогда
		// @skip-check query-in-loop - запрос к разным таблицам.
		ДобавляемыеЗначения = СвойстваНастройки.ЗапросЗначенийВыбора.Выполнить().Выгрузить().ВыгрузитьКолонку(0);
		Для Каждого Элемент Из ДобавляемыеЗначения Цикл
			ОтчетыКлиентСервер.ДобавитьУникальноеЗначениеВСписок(
			СвойстваНастройки.ЗначенияДляВыбора, Элемент, Неопределено, Ложь);
		КонецЦикла;
		СвойстваНастройки.ЗначенияДляВыбора.СортироватьПоПредставлению(НаправлениеСортировки.Возр);
	КонецЕсли;
	
	Если ТипЗнч(СвойстваНастройки.ЗначенияДляВыбора) = Тип("СписокЗначений")
		И СвойстваНастройки.ЗначенияДляВыбора.Количество() > 0 Тогда 
		ОписаниеНастройки.ДоступныеЗначения = СвойстваНастройки.ЗначенияДляВыбора;
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти
